4

我正在尝试将一些自定义类/数据存储到我的 iPhone/iPad 应用程序中的文件中。

我有一个类 RSHighscoreList

@interface RSHighscoreList : NSObject {
    NSMutableArray *list;
}

其中包含列表中 RSHighscore 的对象

@interface RSHighscore : NSObject {
    NSString *playerName;
    NSInteger points;
}

当我尝试将所有内容存储到文件时

- (void)writeDataStore {
    RSDataStore *tmpStore = [[RSDataStore alloc] init];
    _tmpStore.highscorelist = self.highscorelist.list;
    NSMutableData *data = [[NSMutableData alloc] init];
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];

    [archiver encodeObject:tmpStore forKey:kDataKey];
    [archiver finishEncoding];
    [data writeToFile:[self dataFilePath] atomically:YES];

    [archiver release];
    [data release];
}

@interface RSDataStore : NSObject <NSCoding, NSCopying> {
    NSMutableArray *highscorelist; 
}

- (void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:highscorelist forKey:@"Highscorelist"];
}

该应用程序将崩溃并显示错误消息

-[RSHighscore encodeWithCoder:]:无法识别的选择器发送到实例 0x573cc20
*** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[RSHighscore encodeWithCoder:]:无法识别的选择器发送到实例 0x573cc20”

我想知道为什么错误会告诉 RSHighscore,即使它是“包装的”。有人有好主意吗?

4

2 回答 2

10

RSDataStore有一个-encodeWithCoder:方法,但是(根据错误消息)RSHighscore没有。您需要为要序列化的每个类实现NSCoding协议。

@implementation RSHighscore
static NSString *const kPlayerName = @"PlayerName";
static NSString *const kPoints = @"Points";

-(id)initWithCoder:(NSCoder *)decoder {
    if ((self=[super init])) {
        playerName = [[decoder decodeObjectForKey:kPlayerName] retain];
        points = [decoder decodeIntegerForKey:kPoints];
    }
    return self;
}
-(void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:playerName forKey:kPlayerName];
    [encoder encodeInt:points forKey:kPoints];
}
...

如果 的基类RSHighscore曾经更改为 以外的东西NSObject,则-initWithCoder:可能需要将方法更改为 call[super initWithCoder:decoder]而不是[super init]。或者,添加<NSCoding>到 NSObject 并立即更改RSHighscore-initWithCoder:

@interface NSObject (NSCoding)
-(id)initWithCoder:(NSCoder*)decoder;
-(void)encodeWithCoder:(NSCoder*)encoder;
@end

@implementation NSObject (NSCoding)
-(id)initWithCoder:(NSCoder*)decoder {
    return [self init];
}
-(void)encodeWithCoder:(NSCoder*)encoder {}
@end

@implementation RSHighscore
-(id)initWithCoder:(NSCoder *)decoder {
    if ((self=[super initWithCoder:decoder])) {
        playerName = [[decoder decodeObjectForKey:kPlayerName] retain];
        points = [decoder decodeIntegerForKey:kPoints];
    }
    return self;
}
...
于 2010-11-30T18:47:55.380 回答
4

你要编码的类或 initWithCoder 应该符合<NSCoding>协议所以你应该在你的接口中添加它,否则运行时确实不会识别选择器,因为它是<NSCoding>协议的一部分

于 2010-11-30T18:39:36.153 回答