Как освободить контроллеры представления, которые содержат представление, ссылающееся на его родителя - PullRequest
1 голос
/ 13 ноября 2010

Вот интересная проблема. У меня есть контроллер представления, давайте назовем его MyViewController. Одним из его членов является пользовательское представление, назовем это MyCustomView. MyCustomView также имеет ссылку на своего родителя, MyViewController, поскольку MyViewController используется в качестве делегата для пользовательского представления. Проблема возникает, когда MyViewController выгружен, скажем, из-за предупреждения памяти. Вот что происходит:

Во-первых, viewDidUnload вызывается для MyViewController. Это выглядит примерно так:

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

Когда выполняется self.myCustomView = nil, это вызывает освобождение myCustomView. Процедура Deloc для MyCustomView выглядит примерно так:

- (void)dealloc {
    ...
    [delegate release];
    ...
    [super dealloc];
}

Напомним, что делегатом является MyViewController. Если бы MyCustomView были выпущены первыми, это не было бы проблемой, поскольку счетчик ссылок для MyViewController был бы больше 1, но в этом случае MyViewController уже не имеет других ссылок на него. Это приводит к тому, что MyViewController освобождается, а именно вызывается его процедура dealloc, которая выглядит следующим образом:

- (void)dealloc { 
    [myCustomView release];
    [somedata release];
    ...
    [super dealloc];
}

Как вы можете видеть, члены MyViewController, а именно "somedata", получают выпуск ДО завершения процедуры viewDidUnload для MyViewController. Когда подпрограммы dealloc для MyViewController и MyCustomView завершены, и мы возвращаемся к завершению подпрограммы viewDidUnload, мы переходим к строке

self.somedata = nil;

Теперь некоторые данные не равны нулю, но их значение уже выпущено! Это вызывает исключение.

Кажется, это критический недостаток в подсчете ссылок. Как вы справляетесь с двусторонними ссылками в подобных объектах, которые вызывают освобождение друг друга?

Один из ответов - всегда устанавливать нулевые члены в подпрограмме dealloc. Мне не нравится этот ответ. Это много дополнительной работы и не должно быть необходимо большую часть времени. Другой ответ заключается в изменении порядка viewDidUnload, чтобы в конце всегда происходило освобождение дочерних объектов, которые могут иметь обратные указатели. Мне тоже не нравится это решение, и иногда оно может даже не работать.

Как обойти эту проблему?

1 Ответ

5 голосов
/ 13 ноября 2010

членов делегатов, как правило, не учитываются. Как правило, декларация:

@property(nonatomic, assign) id<UITableViewDelegate> delegate

Если вы сделаете своего делегата таким, у вас не будет проблемы. И это должно быть безопасно, так как родительский контроллер представления только вокруг, пока дочернее представление - да?

...