Ошибка при втором сохранении NSManagedObjectContext (освобожденный страховой полис) - PullRequest
0 голосов
/ 09 апреля 2011

Я прочитал несколько веток, посвященных подобным вопросам, здесь, но я просто не могу понять, что я переиздаю.В подробном контроллере для объекта Player я нажимаю UITableViewController, чтобы выбрать объекты Location для этого Player:

- (void)selectLocations 
{
    LocationSelectionController *vc = [[LocationSelectionController alloc] initWithStyle:UITableViewStyleGrouped];
    vc.player = player;
    [self.navigationController pushViewController:vc animated:YES];
    [vc release];
}

Вот некоторые детали LocationSelectionController:

- (void)saveContext {
    NSManagedObjectContext *context = [player managedObjectContext];
    if ([context hasChanges]) {
    NSError *error = nil;
        if (![context save:&error]) { //*** ERROR HERE ***
           // show alert
        }
    }
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // ....

    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
        // show alert
    }
}

- (NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    NSManagedObjectContext *context = [player managedObjectContext];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Location" inManagedObjectContext:context];
    [request setEntity:entity];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)];
    NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
    [request setSortDescriptors:sortDescriptors];

    NSFetchedResultsController *aFRC = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
    aFRC.delegate = self;
    self.fetchedResultsController = aFRC;

    [request release];
    [sortDescriptor release];

    return _fetchedResultsController;
}

- (void)viewDidUnload {
    [super viewDidUnload];
    self.fetchedResultsController = nil;
}


- (void)dealloc {
    self.fetchedResultsController = nil;
    [_fetchedResultsController release];
    [player release];
    [super dealloc];
}

Функциональность всегда идеальна при первом переходе к LocationSelectionController.Я могу без проблем взаимодействовать с объектами Location.Когда я открываю представление и возвращаюсь к подробному виду объекта Player, снова появляется отличная функциональность.Только когда я нажимаю LocationSelectionController во второй раз (даже если он из другого объекта Player), происходит сбой при попытке сохранить контекст.

*** -[LocationSelectionController controllerWillChangeContent:]: message sent to deallocated instance 0x7026920

Я пытался использовать инструментыс NSZombie, чтобы найти проблему, и он указывает мне на экземпляр LocationSelectionController.Instruments Screen

Ответы [ 2 ]

1 голос
/ 09 апреля 2011

Ваша обработка NSFetchedResultsController испорчена.Сначала рассмотрим этот код:

NSFetchedResultsController *aFRC = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
aFRC.delegate = self;
self.fetchedResultsController = aFRC;

Если ваше свойство fetchedResultsController объявлено assign, этот код более или менее правильный (хотя тогда семантика неверна).Если свойство объявлено retain, то здесь вы указываете ссылку aFRC.

Но в любом случае ваше освобождение неверно.В dealloc у вас есть это:

self.fetchedResultsController = nil;
[_fetchedResultsController release];

Первая строка устанавливает для свойства (и это, вероятно, _fetchedResultsController ivar) значение nil, поэтому вторая строка никогда не может освободить объект.Если свойство объявлено retain, я думаю, это попытка устранить утечку, упомянутую выше;если он объявлен assign, это свидетельствует о неверной семантике, упомянутой выше.И даже если это работало «правильно», версия в viewDidUnload не имеет такого дополнительного выпуска, поэтому все еще неправильный.

В любом случае, утечка ссылки оставляет NSFetchedResultsController живым,В конце концов он находит изменение, которое пытается отправить своему делегату.И это, конечно, не получается, потому что делегат уже давно освобожден.


Скорее всего, вам никогда не потребуется назначать fetchedResultsController извне реализации этого класса.Тогда вы действительно должны сделать что-то вроде этого:

Свойство fetchedResultsController должно быть объявлено как:

@property (retain, readonly) NSFetchedResultsController *fetchedResultsController;

С существующим fetchedResultsController все в порядке, за исключением того, что ему следует назначить_fetchedResultsController ivar напрямую вместо попытки присвоения self.fetchedResultsController.

Тогда каждый из методов dealloc и viewDidUnload должен освобождать объект примерно так:

[_fetchedResultsController release];
_fetchedResultsController = nil;

Вы также можете установить _fetchedResultsController.delegate nil перед его выпуском, чтобы быть уверенным, но документация не указывает, что это необходимо, как это делается для некоторых других классов.

0 голосов
/ 15 апреля 2011

У меня была похожая проблема с другим исходом.

В моем случае у меня было несколько наблюдателей KVO в контроллере, у которых не было соответствующего removeObserver: forKeyPath: вызовы в dealloc.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...