Dealloc называют дважды?

Resloved!

Благодаря "Одинокому стрелку" эта проблема возникла из-за недосмотра того, как многие делегаты не установили ноль перед их освобождением.

Это странно... Я знаком с основами управления памятью, но думаю, что-то необычное в том, что я вижу. Вот небольшой фон...

У меня есть NavigationController, который обрабатывает переход между следующими ViewController:

Домой -> Игры -> Игра

При запуске кода он падает при выходе из игры. В GameViewController есть метод dealloc, который похож на:

- (void)dealloc 
{
    [board release];
    [opponentsViewController release];
    [instructionsViewController release];
    [imgPicker release];
    [gameView release];
    [super dealloc];
}

Когда контроллер навигации возвращается к списку игр (из игры), он выдает EXC_BAD_ACCESS. Поэтому я поднимаю свой верный профилировщик и проверяю зомби. Увы, как я и ожидал, сообщение отправляется на освобожденный объект! Копая глубже, я нахожу там 3 записи в истории объекта:

  1. Выдача доски (вызывается методом init игры)
  2. Выпуск доски (вызывается методом dealloc в игре)
  3. 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];
Другие вопросы по тегам