xcode iPhone - 归档自定义对象数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2814316/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 19:21:12  来源:igfitidea点击:

iPhone - archiving array of custom objects

iphoneobjective-cxcodesdk

提问by Dylan

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

游戏存档

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

件.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:
[NSKeyedArchiver archiveRootObject:savedGames toFile:[self dataFilePath]];

设置了一些断点后,从 -saveGame:
[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.

如果重要的话, -saveGame 从导航控制器中的 UIBarButton 调用。

Any help is appreciated, thanks.

任何帮助表示赞赏,谢谢。

回答by benzado

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. In your code you are leaking that instance. You should be doing this:

initWithCoder:被调用时,类的一个实例已经被分配。在您的代码中,您正在泄漏该实例。你应该这样做:

- (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 saveGamemethod has several problems.

此外,您的saveGame方法有几个问题。

  1. If savedGamesis nil, you are saving an object, not an array, to the file. 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 NSMutableArraydoesn't matter, if you archive a mutable array you will get an immutable one on unarchive. You need to call mutableCopyon the unarchived array if you want to modify it.
  1. 如果savedGames为 nil,则将对象而不是数组保存到文件中。这意味着在下一次运行时,未归档的对象将不是您期望的数组。
  2. 未归档的数组是不可变的。声明类型NSMutableArray无关紧要,如果您归档一个可变数组,您将在取消归档时得到一个不可变数组。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.

我不确定异常,确切地说,但解决上述问题,要么它会消失,要么解决方案会变得更容易找到。

回答by buley

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