Освободить в viewDidUnload и освободить оба?

Некоторое время я полагал, что viewDidUnload всегда вызывается, когда контроллер освобождается. Это правильное предположение?

Я только что исследовал некоторые странности и установил точку останова в viewDidUnload своего контроллера, и это dealloc. Похоже, что dealloc вызывается, но метод viewDidUnload никогда не вызывается. Я даже добавил self.view = nil к своему dealloc, но он все равно не вызвал его.

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

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


Более конкретный пример в новом проекте на SDK 3.1.2:

@implementation TestViewController

@synthesize label;

- (IBAction)push {
    TestViewController *controller = [[[TestViewController alloc] initWithNibName:@"TestViewController" bundle:nil] autorelease];
    [self.navigationController pushViewController:controller animated:YES];
}

- (void)viewDidUnload {
    self.label = nil;
    NSLog(@"viewDidUnload was called");
}

- (void)dealloc {
    [super dealloc];
    NSLog(@"label retain count: %i", [label retainCount]);
}

@end

Мой делегат приложения создает простой контроллер навигации с одним из них в качестве корневого контроллера. Когда я нажимаю кнопку, связанную с push 3 раза, а затем трижды нажимаю кнопку «Назад», создается следующий результат.

ViewDidUnloadTest[2887:207] label retain count: 2
ViewDidUnloadTest[2887:207] label retain count: 2
ViewDidUnloadTest[2887:207] label retain count: 2

Что на 2 выше, чем я мог бы подумать. Один раз сохраняется представлением и один раз контроллером. Но после dealloc я ожидал, что представление исчезнет, ​​выпустив мою метку, а контроллер исчезнет, ​​вызывая viewDidUnload и отпуская его. Хотя там может быть autorelease, сбивающее счет на этом этапе.

Но по крайней мере ясно, что viewDidUnload вообще не вызывается, что противоречит этому ответу здесь: Всегда ли вызываются viewDidUnload и dealloc при разрыве UIViewController?

Возможно, мне следует просто вызвать [self viewDidUnload] во всех моих методах освобождения контроллеров? Хуже того, что я дважды устанавливаю для свойства значение nil, верно?


person Alex Wayne    schedule 01.03.2010    source источник


Ответы (1)


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

Если вам действительно нужно освободить их где-нибудь еще, всегда устанавливайте ссылку на nil после release. Это защитит ваше приложение от взрыва позже (вероятно, в dealloc).

Обратите внимание, что в документации явно указывается, что свойство view уже будет равно нулю при вызове viewDidUnload.

person bbum    schedule 01.03.2010
comment
Итак, вы говорите: да, вам нужно освободить сохраненные свойства в вашем dealloc, даже если вы освободите и аннулируете их в своем viewDidUnload методе? - person Alex Wayne; 01.03.2010
comment
Точно; viewDidUnload предназначен для ситуаций с нехваткой памяти, а dealloc - для очистки. Эти два ортогональны. - person bbum; 01.03.2010
comment
Это очень запутанный момент, исходя из примеров! Большинство примеров показывают, что в viewDidUnload установлено значение nil. Что он не может объяснить, так это то, что после того, как что-то установлено в nil, вы не можете освободить его и ожидать, что оно освободится! Не обращая на это внимания, вы получите повсюду утечки памяти. Спасибо за ваш полезный пост. - person jocull; 06.11.2010
comment
@jocull Установка для сохраненного свойства значения nil фактически освободит его, что приведет к его освобождению до тех пор, пока у вас нет другой сохраненной ссылки где-то еще. - person Nick Forge; 02.02.2011
comment
@ Ник, я не мог этого добиться. Можете ли вы указать мне на любую документацию, которая более подробно объясняет это? - person jocull; 02.02.2011
comment
В этом весь смысл сохраненного свойства - когда вы вызываете setFoo:, старое значение foo освобождается, а новое сохраняется. Прочтите об атрибуте свойства retain здесь: developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ - person Nick Forge; 02.02.2011
comment
@Nick Это происходит, только если вы используете [setFoo:nill];, или это также работает, если вы используете somevar.Foo = nil;? - person jocull; 03.02.2011
comment
@jocull [foo setBar:nil]; будет скомпилирован в точно такой же двоичный файл, что и foo.bar = nil; - они точно эквивалентны (пока foo имеет объявленный метод setBar:). - person Nick Forge; 04.02.2011
comment
Обратите внимание, что [foo setBar: nil] и foo.bar = nil освобождают сохраненное свойство, bar = nil (если bar является локальным для вызова) НЕ будет, и у вас будет утечка. Вам нужно будет сделать [bar release], bar = nil; в этом случае. - person Cory Imdieke; 16.02.2011
comment
Ага - и [bar release]; без bar = nil; с радостью создает висящий указатель! - person bbum; 16.02.2011
comment
Я создал объект класса и выпуска и установил ноль. и перераспределить инициализировать его. . . . но выпущенный объект не убивает его задачу. как я убиваю все задачи, запущенные объектом. - person Amit Battan; 01.08.2012