2010-11-30 3 views
4

Я пытаюсь сохранить некоторые пользовательские классы/данные в файл в приложении iPhone/iPad.Сохранить собственный класс с NSCoder

У меня есть класс 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:]: unrecognized selector sent to instance 0x573cc20 
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[RSHighscore encodeWithCoder:]: unrecognized selector sent to instance 0x573cc20'

Интересно, почему ошибка говорит о RSHighscore, даже если это «завернуто». У кого-нибудь есть хорошая идея?

+0

Можете ли вы показать нам свою реализацию encodeWithCoder для HighScoreList. – deanWombourne 2010-11-30 18:33:46

+0

есть в конце. – Stef 2010-11-30 18:38:58

+0

Является ли `RSHighscoreList` используемым в фактическом коде? Это не в образце. Не использовать его не вызовет проблем, но если вы его используете, вам также может понадобиться реализовать NSCoding для `RSHighscoreList`. – outis 2010-11-30 18:49:54

ответ

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:, возможно, потребуется изменить, чтобы позвонить [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; 
} 
... 
4

класс вы собираетесь кодировать или initWithCoder должны соответствовать <NSCoding> протоколу Таким образом, вы просто должны добавить это в интерфейсе, в противном случае действительно среда выполнения не распознает селектор, как это часть <NSCoding> протокола

Смежные вопросы