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 が「ラップ」されているにもかかわらず、なぜエラーが 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:呼び出す必要がある場合があります。または、 NSObjectに追加して、今すぐ変更します。[super initWithCoder:decoder][super init]<NSCoding>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 に答える