【问题标题】:iPhone - archiving array of custom objectsiPhone - 归档自定义对象数组
【发布时间】:2010-05-11 20:45:51
【问题描述】:

我已经尝试了几个小时,但我无法解决这个问题。

我正在制作一个保存未完成的国际象棋游戏的应用程序,因此我正在尝试将数组写入文件。

如果有意义的话,这就是数组:

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

一块.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 调用。

感谢您的帮助。

【问题讨论】:

  • 您忘记发布问题了。代码的具体问题是什么?
  • 对不起,我编辑了我原来的帖子有具体问题。

标签: iphone objective-c xcode sdk


【解决方案1】:

这是错误的:

- (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 为 nil,则您正在将对象而不是数组保存到文件中。这意味着在下一次运行时,未归档的对象将不会是您期望的数组。
  2. 未归档的数组是不可变的。将类型声明为NSMutableArray 并不重要,如果您归档一个可变数组,您将在取消归档时获得一个不可变数组。如果你想修改它,你需要在未归档的数组上调用mutableCopy

我不确定该异常究竟是什么,但如果解决上述问题,它就会消失,或者解决方案会变得更容易找到。

【讨论】:

  • 非常感谢,这解决了错误!我肯定会更多地研究内存管理。
【解决方案2】:

如果你不能让你的 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];
 ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    • 2010-10-29
    • 1970-01-01
    • 2023-04-02
    • 2016-05-10
    • 1970-01-01
    相关资源
    最近更新 更多