Dealloc называют дважды?
Resloved!
Благодаря "Одинокому стрелку" эта проблема возникла из-за недосмотра того, как многие делегаты не установили ноль перед их освобождением.
Это странно... Я знаком с основами управления памятью, но думаю, что-то необычное в том, что я вижу. Вот небольшой фон...
У меня есть NavigationController, который обрабатывает переход между следующими ViewController:
Домой -> Игры -> Игра
При запуске кода он падает при выходе из игры. В GameViewController есть метод dealloc, который похож на:
- (void)dealloc
{
[board release];
[opponentsViewController release];
[instructionsViewController release];
[imgPicker release];
[gameView release];
[super dealloc];
}
Когда контроллер навигации возвращается к списку игр (из игры), он выдает EXC_BAD_ACCESS. Поэтому я поднимаю свой верный профилировщик и проверяю зомби. Увы, как я и ожидал, сообщение отправляется на освобожденный объект! Копая глубже, я нахожу там 3 записи в истории объекта:
- Выдача доски (вызывается методом init игры)
- Выпуск доски (вызывается методом dealloc в игре)
- Board - это Zombie'd (вызывается методом dealloc в Game)
Оба вызова 2 и 3 вызываются из UINavigationController setDisappearingViewController.
В моем методе dealloc я устанавливал контрольные точки для каждого вызова освобождения, при этом происходит вызов [board release], затем происходит вызов [oppentsViewController release], затем снова вызывается вызов [board release]. Итак, я вижу, что метод dealloc не завершается полностью и вызывает снова.
Что может быть причиной этого?
Редактировать: это реализация GameViewController
Код от контроллера игр, который добавляет эту игру:
-(void) gotoGame:(int)tag {
game = [[GameViewController alloc] init];
[self.navigationController pushViewController:game animated:YES];
[game release];
}
Изменить: это заголовок GameViewController
2 ответа
Я бы попытался установить все делегаты вашего ивара на ноль (РЕДАКТИРОВАТЬ: в dealloc). У меня была похожая проблема с контроллером полученных результатов. Не удалось установить для его делегата значение nil в dealloc, и в стеке данных ядра все еще имел указатель на него, когда контроллер представления был освобожден.
Так что это моя ставка, установите для делегатов ivar значение nil в dealloc, хотя я не вижу вашего заголовка, чтобы знать, какие протоколы вы соблюдаете, чтобы быть уверенным.
РЕДАКТИРОВАТЬ: объяснение
Установка делегата фактически дает объекту, который выполняет делегирование, указатель (я полагаю, что это обычно назначенное свойство).
@property (assign) delegate;
Я буду использовать проблему, которую я имел в качестве примера.
Итак, допустим, у вас есть контроллер представления, который имеет fetchedResultsController в качестве ivar. Когда вы устанавливаете делегат FRC:
fetchedResultsController.delegate = self;
и контроллер представления освобождается, любой объект, который использует этот указатель, все еще думает, что он живой. Вы могли бы подумать, что поскольку FRC выпускается и в dealloc, у вас все будет в порядке (вот почему мне понадобилось 4 дня, чтобы понять это:)), но иногда другие части реализации также используют вашего делегата. Итак, исправление:
-(void)dealloc
{
self.fetchedResultsController.delegate = nil;
[_fetchedResultsController release];
[super dealloc];
}
Примечание: как только новые инструменты станут доступны всем, вам больше не придется об этом беспокоиться ^ ^;
Пытаться
- (void) dealloc {
if(game != nil){
//release here
[game release];
}
[super dealloc];
}
Кстати, кажется, что вы объявили игру в заголовочном файле, и сразу после нажатия вы отпускаете ее, а также в методе dealloc вы отпускаете ее. Либо удалите вызов release из метода dealloc, либо измените свой метод следующим образом.
-(void) gotoGame:(int)tag {
GameViewController *game = [[GameViewController alloc] init];
[self.navigationController pushViewController:game animated:YES];
[game release];
}
ОБНОВИТЬ
Также вы нигде не используете тег. Почему бы вам не создать свой метод инициализации, как этот
GameViewController *game = [[GameViewController alloc] initWithTag:tag];
[self.navigationController pushViewController:game animated:YES];
[game release];