Как кодировать и декодировать пользовательский класс с помощью NSKeyedArchiver

У меня есть собственный класс, который я хочу сохранить и загрузить. Класс содержит NSDate, NSString и NSNumber. Я реализовал протокол NSCoding в файле .h. Вот код, который у меня есть. theDate - это NSDate. Имя - это NSString. homeAway - это NSNumber.

-(void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:theDate forKey:@"theDate"];
[aCoder encodeObject:theName forKey:@"theName"];
[aCoder encodeObject:homeAway forKey:@"homeAway"];
}

-(id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super init])) {
    theDate = [aDecoder decodeObjectForKey:@"theDate"];
    theName = [aDecoder decodeObjectForKey:@"theName"];
    homeAway = [aDecoder decodeObjectForKey:@"homeAway"];
}
return self;
}

Я использую приведенный ниже код для загрузки своего настраиваемого объекта. Когда я использую print-object в отладчике, только homeAway отображается как реальный объект. theDate и theName говорят, что 0x4e4f150 не указывает на действительный объект.

[gamesArray setArray:[NSKeyedUnarchiver unarchiveObjectWithFile:path]];  
Game *loadedGame = [gamesArray objectAtIndex:gameNumber];

Я сохраняю данные, используя следующий код:

Я использую это, чтобы вызвать свой класс для создания новой игры (настраиваемый класс, который я пытаюсь сохранить). Код до NSDate * aDate = [gameDate date]; не имеет значения.

-(void)newGame {
if (homeAway != 0) {
    if (dateChanged == 1) {
        if ([nameField.text length] > 0) {
            [homeButton setImage:[UIImage imageNamed:@"HomeGray.png"] forState:UIControlStateNormal];
            [awayButton setImage:[UIImage imageNamed:@"AwayGray.png"] forState:UIControlStateNormal];
            [dateButton setImage:[UIImage imageNamed:@"DateGray.png"] forState:UIControlStateNormal];
            [nameField setBackground:[UIImage imageNamed:@"textField.png"]];
            NSDate *aDate = [gameDate date];
            NSString *aString = [[[NSString alloc] initWithString:[nameField text]] autorelease];
            UIApplication *app = [UIApplication sharedApplication];
            [[[(miShotTrackAppDelegate *)[app delegate] viewController] courtViewOne] newGame:aDate withName:aString andPlace:homeAway];
            [loadTable reloadData];
            datePicke = 0;
            homeAway = 0;
            dateChanged = 0;
            nameField.text = @"";
            [self goBack];
            [self autoSave];
        }
    }
}

}

Из этого метода я вызываю метод newGame, который

-(void)newGame:(NSDate *)theDate withName:(NSString *)theName andPlace:(int)homeAway {

Game *newGame = [[Game alloc] init];
NSDate *tDate = [NSDate new];
tDate = theDate;
[newGame setTheDate:tDate];
NSString *tString = [NSString stringWithString:theName];
[newGame setTheName:tString];
NSNumber *theNumber = [NSNumber numberWithInt:homeAway];
[newGame setHomeAway:theNumber];
[gamesArray addObject:newGame];
gameNumber = [gamesArray count] - 1;
NSString *path = [self findGamesPath];
[NSKeyedArchiver archiveRootObject:gamesArray toFile:path];
[newGame release];
}

Почему мои объекты не сохраняются? Имеет ли какое-то отношение к этому копирование моих объектов? Я получаю сообщение об ошибке в строке с комментарием "exc bad access". Пожалуйста помоги...


person Blane Townsend    schedule 24.04.2011    source источник


Ответы (1)


Вы неправильно реализуете -initWithCoder. -decodeObjectForKey возвращает автоматически выпущенный объект. Таким образом, как вы написали метод, вы в конечном итоге получаете висячие указатели для всех ваших игровых ivars. Измените -initWithCoder на:

-(id)initWithCoder:(NSCoder *)aDecoder 
{
  if ((self = [super init])) {
    [self setTheDate:[aDecoder decodeObjectForKey:@"theDate"]];
    [self setTheName:[aDecoder decodeObjectForKey:@"theName"]];
    [self setHomeAway:[aDecoder decodeObjectForKey:@"homeAway"]];
  }
  return self;
}

и это должно сработать для вас.

person McCygnus    schedule 24.04.2011
comment
Спасибо тебе за это! Я должен добавить к этому сообщению: Не забывайте также вызывать функции super! Если вы этого не сделаете, вы получите странные результаты. Итак: if ((self = [super initWithCoder:aDecoder])) { в приведенном выше примере. - person Ramon; 17.01.2017