使用 NSCoder 保存自己的类

发布于 2024-10-05 14:49:46 字数 1349 浏览 7 评论 0原文

我正在尝试将一些自定义类/数据存储到我的 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"];
}

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

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

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

I'm trying to store some custom class/data to a file in my iPhone/iPad app.

I have a Class RSHighscoreList

@interface RSHighscoreList : NSObject {
    NSMutableArray *list;
}

which contains objects of RSHighscore in the list

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

When I try to store all to file

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

The app will crash with an error message

-[RSHighscore encodeWithCoder:]: unrecognized selector sent to instance 0x573cc20
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[RSHighscore encodeWithCoder:]: unrecognized selector sent to instance 0x573cc20'

I wonder why the error tells about RSHighscore, even if that is 'wrapped'. Does anyone have a good idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

番薯 2024-10-12 14:49:46

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: 方法以调用 >[super initWithCoder:decoder] 而不是 [super init]。或者,将 添加到 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;
}
...

RSDataStore has an -encodeWithCoder: method, but (according to the error message) RSHighscore doesn't. You need to implement the NSCoding protocol for every class you're serializing.

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

If the base class of RSHighscore is ever changed to something other than NSObject, the -initWithCoder: method might need to be changed to call [super initWithCoder:decoder] rather than [super init]. Alternatively, add <NSCoding> to NSObject and change RSHighscore's -initWithCoder: now.

@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;
}
...
烟雨凡馨 2024-10-12 14:49:46

您要编码或 initWithCoder 的类应符合 协议
因此,您应该将其添加到界面中,否则运行时实际上将无法识别选择器,因为它是 协议的一部分

The class you're going to encode or initWithCoder should conform to <NSCoding> protocol
So you just should add this in your interface, otherwise indeed the runtime will not recognize the selector as it's the part of <NSCoding> protocol

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文