2010-05-11 75 views
3

我一直在嘗試幾個小時,我無法解決這個問題。iPhone - 自定義對象的歸檔陣列

我正在製作一個保存未完成國際象棋遊戲的應用程序,所以我正在嘗試將一個數組寫入一個文件。

這就是數組是什麼,如果它是有道理的:

-NSMutableArray savedGames 
--GameSave a 
---NSMutableArray board; 
----Piece a, b, c, etc. 
-----some ints 
---NSString whitePlayer, blackPlayer; 
---int playerOnTop, turn; 
--GameSave b 
---NSMutableArray board; 
----Piece a, b, c, etc. 
-----some ints 
---NSString whitePlayer, blackPlayer; 
---int playerOnTop, turn; 

這些都是我NSCoding方法:

GameSave.m

- (void)encodeWithCoder:(NSCoder *)coder { 
    [coder encodeObject:whitePlayer forKey:@"whitePlayer"]; 
    [coder encodeObject:blackPlayer forKey:@"blackPlayer"]; 
    [coder encodeInt:playerOnTop forKey:@"playerOnTop"]; 
    [coder encodeInt:turn forKey:@"turn"]; 
    [coder encodeObject:board forKey:@"board"]; 
} 

- (id)initWithCoder:(NSCoder *)coder { 
    self = [[GameSave alloc] init]; 
    if (self != nil) 
    { 
     board = [coder decodeObjectForKey:@"board"]; 
     whitePlayer = [coder decodeObjectForKey:@"whitePlayer"]; 
     blackPlayer = [coder decodeObjectForKey:@"blackPlayer"]; 
     playerOnTop = [coder decodeIntForKey:@"playerOnTop"]; 
     turn = [coder decodeIntForKey:@"turn"]; 
    } 
    return self; 
} 

Piece.m

- (void)encodeWithCoder:(NSCoder *)coder { 
    [coder encodeInt:color forKey:@"color"]; 
    [coder encodeInt:piece forKey:@"piece"]; 
    [coder encodeInt:row forKey:@"row"]; 
    [coder encodeInt:column forKey:@"column"]; 
} 

- (id)initWithCoder:(NSCoder *)coder { 
    self = [[Piece alloc] init]; 
    if (self != nil) 
    { 
     color = [coder decodeIntForKey:@"color"]; 
     piece = [coder decodeIntForKey:@"piece"]; 
     row = [coder decodeIntForKey:@"row"]; 
     column = [coder decodeIntForKey:@"column"]; 
    } 
    return self; 
} 

這是一種嘗試歸檔並保存到文件中的代碼:

- (void)saveGame { 
    ChessSaverAppDelegate *delegate = (ChessSaverAppDelegate *) [[UIApplication sharedApplication] delegate]; 
    [[delegate gameSave] setBoard:board]; 

    NSMutableArray *savedGames = [NSKeyedUnarchiver unarchiveObjectWithFile:[self dataFilePath]]; 
    if (savedGames == nil) { 
     [NSKeyedArchiver archiveRootObject:[delegate gameSave] toFile:[self dataFilePath]]; 
    } else { 
     [savedGames addObject:[delegate gameSave]]; 
     [NSKeyedArchiver archiveRootObject:savedGames toFile:[self dataFilePath]]; 
    } 
} 

- (NSString *)dataFilePath { 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    return [documentsDirectory stringByAppendingPathComponent:@"gameSaves.plist"]; 
} 

對不起,這裏的問題:

設置一些斷點後,這條線從-saveGame後得出一個錯誤:
[NSKeyedArchiver archiveRootObject:savedGames toFile:[self dataFilePath]];

而且這是在控制檯中顯示的內容:

2010-05-11 17:04:08.852 ChessSaver[62065:207] *** -[NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x3d3cd30 
2010-05-11 17:04:08.891 ChessSaver[62065:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x3d3cd30' 
2010-05-11 17:04:08.908 ChessSaver[62065:207] Stack: (
    32339035, 
    31077641, 
    32720955, 
    32290422, 
    32143042, 
    238843, 
    25827, 
    238843, 
    564412, 
    342037, 
    238843, 
    606848, 
    17686, 
    2733061, 
    4646817, 
    2733061, 
    3140430, 
    3149167, 
    3144379, 
    2837983, 
    2746312, 
    2773089, 
    41684313, 
    32123776, 
    32119880, 
    41678357, 
    41678554, 
    2777007, 
    9884, 
    9738 
) 

如果它的事項,-saveGame從UIBarButton在導航控制器調用。

任何幫助表示讚賞,謝謝。

+0

你忘了張貼問題。代碼的特殊問題是什麼? – stigi 2010-05-11 20:48:32

+0

對不起,我編輯了我的原始文章與特定的問題。 – Dylan 2010-05-11 21:09:38

回答

7

這是錯誤的:

- (id)initWithCoder:(NSCoder *)coder { 
    self = [[Piece alloc] init]; 
    if (self != nil) 
    { 

的時候initWithCoder:被稱爲類的實例已經分配。在你的代碼中,你正在泄露該實例。你應該這樣做:

- (id)initWithCoder:(NSCoder *)coder { 
    self = [super init]; // or [self init] if needed 
    if (self != nil) 
    { 

此外,當你解碼一個對象,你不擁有它,所以你需要保留它。

board = [[coder decodeObjectForKey:@"board"] retain]; 

如果你沒有「得到」保留/釋放規則,現在就去學習它們,或者你會不斷地在腳下射擊自己。

此外,您的saveGame方法有幾個問題。

  1. 如果savedGames爲零,則表示您將一個對象而不是數組保存到文件中。這意味着下一次運行時,未存檔的對象將不會像您期望的那樣是一個數組。
  2. 未歸檔的數組是不可變的。將類型聲明爲NSMutableArray並不重要,如果將一個可變數組存檔,您將得到一個不可變的數組。如果你想修改它,你需要在未存檔的數組上調用mutableCopy

我並不確定這個異常,但是修正了上述問題,並且它會消失或者解決方案會變得更容易找到。

+0

非常感謝,這解決了錯誤!我絕對會更多地關注內存管理。 – Dylan 2010-05-11 21:32:00

0

如果你不能讓你的NSKeyedArchiver工作,也許是另一種選擇是將writeToFile:

- (NSString *) saveFilePath:(NSString*)fileName { 
NSArray *saveFilePathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString *filePath = [[NSString alloc] initWithFormat:@"%@.extension", fileName]; 
return [[saveFilePathArray objectAtIndex:0] stringByAppendingPathComponent:filePath]; 
[saveFilePathArray release]; 
[filePath release]; 
} 

... 
NSMutableArray *yourUnsavedGameObject = [[NSMutableArray alloc] initWithArray:yourUnsavedGame]; 
// Write the dictionary to a file 
[yourUnsavedGameObject writeToFile:[self saveFilePath] atomically:YES]; 
...