Не могу понять, почему мое приложение вылетает при использовании NSKeyedArchivers / NSKeyedUnarchivers

#iphone #objective-c #uitableview #nskeyedarchiver #nscoding

#iPhone #objective-c #uitableview #nskeyedarchiver #nscoding

Вопрос:

Я разрабатываю свое первое приложение «Дневник» для iphone, которое использует пользовательские объекты «Запись», содержащие заголовок NSString, текст NSString и дату создания NSDate. Когда я пытаюсь заархивировать NSMutableArray объектов Entry, а затем извлечь их при следующей загрузке view, приложение выходит из строя. Я просмотрел кучу примеров кодов и примеров, которые используют NSKeyedArchivers, но все еще не мог понять, почему это происходит. Я предполагаю, что есть проблема с инициализацией массива, который содержит записи, но не уверен…

Вот код, может быть, вы могли бы найти что-то, за чем я постоянно наблюдал … «

 //--------- Entry.m---------------

- (id) initWithCoder:(NSCoder *)aDecoder{

if ((self = [super init])) {
    self.title = [[aDecoder decodeObjectForKey:@"title"] retain];
    self.text = [[aDecoder decodeObjectForKey:@"text"] retain];
    self.created = [[aDecoder decodeObjectForKey:@"created"] retain];
}
return self;

}

- (void) encodeWithCoder:(NSCoder *)aCoder{

[aCoder encodeObject:self.title forKey:@"title"];
[aCoder encodeObject:self.text forKey:@"text"];
[aCoder encodeObject:self.created forKey:@"created"];

}

//-------------- Diary View Controller.m

- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
     NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}

- (void) writeDataToArchive {
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]
                             initForWritingWithMutableData:data];

[archiver encodeObject:self.entriesArray forKey:@"entriesArray"];
[archiver finishEncoding];
BOOL result = [data writeToFile:[self dataFilePath]  atomically:YES];
[archiver release];
[data release];    
}

- (void)addItem:sender {
int count = [entriesArray count]  1;    
NSString *newEntryTitle = [NSString stringWithFormat:@"Entry %d", count];    
Entry *anEntry = [[Entry alloc] initWithTitle:newEntryTitle text:@"-" 
         created:[NSDate date]];
[entriesArray addObject:anEntry];
[self.tableView reloadData];

[anEntry release];
[self writeDataToArchive];
}

- (void)viewDidLoad
{
[super viewDidLoad];
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {     
     NSData *data = [[NSMutableData alloc]
                     initWithContentsOfFile:[self dataFilePath]];

     NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]
          initForReadingWithData:data];
     NSMutableArray *array = [unarchiver decodeObjectForKey:@"entriesArray"];     
     entriesArray = [array mutableCopy];
     [array release];
     [unarchiver finishDecoding];
     [unarchiver release];
     [data release];
}
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
    (NSIndexPath *)indexPath
{
    // ... some other stuff
     NSUInteger row = indexPath.row;
     Entry *entry = [entriesArray objectAtIndex:row];

     cell.textLabel.text = entry.title;
     return cell;
}
  

Большое спасибо.

Ответ №1:

Когда вы считываете массив обратно с помощью NSKeyedUnarchivers, вы всегда получаете неизменяемую копию обратно. Вам нужно было бы объявить * array как NSArray или просто избавиться от всего массива вместе.

 entriesArray = [[unarchiver decodeObjectForKey:@"entriesArray"] mutableCopy]; 
  

И @JeremyP указывает на другую проблему. Поскольку вы не выделили или не сохранили * array, вам не следует его выпускать.

Ответ №2:

Вы не должны выпускать его array в viewDidLoad , потому что оно вам не принадлежит.

Пожалуйста, ознакомьтесь с Правилами управления памятью Cocoa, потому что в вашем коде есть пара других проблем с управлением памятью. В частности,

 self.title = [[aDecoder decodeObjectForKey:@"title"] retain];
self.text = [[aDecoder decodeObjectForKey:@"text"] retain];
self.created = [[aDecoder decodeObjectForKey:@"created"] retain];
  

в вашем initWithCoder: методе все утечки исходят из предположения, что свойства сохраняются или копируются.

Комментарии:

1. Спасибо, я изучу это. И, в частности, приложение вылетает при загрузке view. Я мог бы отследить это там, используя точки останова, но не понял конкретно, какая строка вызывает это.

2. Изначально у меня были заголовок и текст в виде NSStrings, и у них были свойства «копировать», поэтому я изменил «сохранить» на «копировать». Спасибо.