简体   繁体   English

iPhone - 归档自定义对象数组

[英]iPhone - archiving array of custom objects

I've been trying for hours and I cannot solve this problem. 我已经尝试了几个小时,我无法解决这个问题。

I'm making an app that saves unfinished Chess Games, so I'm trying to write an array to a file. 我正在制作一个可以保存未完成的国际象棋游戏的应用程序,所以我正在尝试将数组写入文件。

This is what the array is, if it makes sense: 如果有意义的话,这就是数组:

-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;

etc. 等等

And these are my NSCoding methods: 这些是我的NSCoding方法:

GameSave.m 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 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;
}

And this is the code that tries to archive and save to file: 这是试图存档并保存到文件的代码:

- (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"];
}

Sorry, here's the problem: 对不起,这是问题所在:

After setting some breakpoints, an error is reached after this line from -saveGame: 设置一些断点后,在-saveGame的这一行之后会出现错误:
[NSKeyedArchiver archiveRootObject:savedGames toFile:[self dataFilePath]]; [NSKeyedArchiver archiveRootObject:savedGames toFile:[self dataFilePath]];

And this is what shows up in the console: 这就是控制台中显示的内容:

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
)

If it matters, -saveGame is called from a UIBarButton in a navigation controller. 如果重要,则从导航控制器中的UIBarButton调用-saveGame。

Any help is appreciated, thanks. 任何帮助表示赞赏,谢谢。

This is wrong: 这是错的:

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

By the time initWithCoder: is called an instance of the class has already been allocated. initWithCoder:被调用时,已经分配了类的实例。 In your code you are leaking that instance. 在您的代码中,您正在泄漏该实例。 You should be doing this: 你应该这样做:

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

Also, when you decode an object, you don't own it, so you need to retain it. 此外,当您解码对象时,您不拥有它,因此您需要保留它。

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

If you don't "get" retain/release rules, learn them now, or you will be continually shooting yourself in the foot. 如果你没有“获得”保留/释放规则,现在就学习它们,否则你将不断地用脚射击。

Also, your saveGame method has several problems. 此外,您的saveGame方法有几个问题。

  1. If savedGames is nil, you are saving an object, not an array, to the file. 如果savedGames为nil,则表示将对象而不是数组保存到文件中。 That means on the next run, the unarchived object will not be an array as you expect. 这意味着在下次运行时,未归档的对象将不是您期望的数组。
  2. Unarchived arrays are immutable. 未归档的数组是不可变的。 Declaring the type to NSMutableArray doesn't matter, if you archive a mutable array you will get an immutable one on unarchive. 将类型声明为NSMutableArray并不重要,如果归档可变数组,则将在unarchive上获得不可变数组。 You need to call mutableCopy on the unarchived array if you want to modify it. 如果要修改它,则需要在unarchived数组上调用mutableCopy

I'm not sure about the exception, exactly, but fix the above problems and either it will go away or the solution will become easier to find. 我完全不确定异常,但是修复了上述问题,要么它会消失,要么解决方案会变得更容易找到。

If you can't get your NSKeyedArchiver to work, perhaps another option would be writeToFile: 如果你不能让你的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];
 ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM