iPhone——定制对象的归档数组。

时间:2022-02-06 17:49:31

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:

这些是我的研究方法:

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:
[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.

非常感谢您的帮助,谢谢。

2 个解决方案

#1


7  

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 saveGame method has several problems.

而且,您的saveGame方法有几个问题。

  1. If savedGames is 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. 如果savedGames为nil,则将对象(而不是数组)保存到文件中。这意味着在下一次运行时,未归档的对象将不是您期望的数组。
  3. 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. You need to call mutableCopy on the unarchived array if you want to modify it.
  4. 从未归档数组是不可变的。将类型声明为NSMutableArray并不重要,如果存档一个可变数组,那么unarchive上就会有一个不变的数组。如果要修改未归档的数组,需要对其调用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.

我不确定是否有例外,但是解决了上面的问题,要么它会消失,要么解决方案会更容易找到。

#2


0  

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

#1


7  

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 saveGame method has several problems.

而且,您的saveGame方法有几个问题。

  1. If savedGames is 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. 如果savedGames为nil,则将对象(而不是数组)保存到文件中。这意味着在下一次运行时,未归档的对象将不是您期望的数组。
  3. 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. You need to call mutableCopy on the unarchived array if you want to modify it.
  4. 从未归档数组是不可变的。将类型声明为NSMutableArray并不重要,如果存档一个可变数组,那么unarchive上就会有一个不变的数组。如果要修改未归档的数组,需要对其调用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.

我不确定是否有例外,但是解决了上面的问题,要么它会消失,要么解决方案会更容易找到。

#2


0  

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