Когда мне следует выпускать объекты в - (void) viewDidUnload, а не в -dealloc?

103

Для чего это -(void)viewDidUnloadнужно?

Могу ли я просто не раскрыть все -dealloc? Если бы представление действительно выгружалось, все равно не -deallocвызывали бы?

Спасибо
источник

Ответы:

51

В дополнение к тому, что уже было указано, я хотел подробнее остановиться на логике -viewDidUnload.

Одна из наиболее важных причин для его реализации заключается в том, что UIViewControllerподклассы обычно также содержат ссылки-владельцы на различные подпредставления в иерархии представлений. Эти свойства могли быть установлены, например, IBOutletsпри загрузке из пера или программно внутри -loadView.

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

Объекты, которые вы выпускаете здесь, обычно воссоздаются и снова устанавливаются при UIViewControllerпросмотре re-loadedлибо из пера, либо посредством реализации -loadView.

Также обратите внимание, что UIViewController viewсвойство находится nilна момент вызова этого метода.

Шон Патрик Мерфи
источник
1
Вам следует прочитать developer.apple.com/library/ios/#featuredarticles/…, чтобы понять жизненный цикл контроллера представления / представления
Пол Солт
21

Как говорится в документации :

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

В такую ​​же ситуацию неdealloc вызывается . Этот метод доступен только в OS3 и выше. Разобраться с такой же ситуацией в iPhone OS 2.x было настоящей головной болью!

Обновление от июля 2015 г. Следует отметить, что viewDidUnloadв iOS 6 эта функция устарела, поскольку «представления больше не очищаются в условиях нехватки памяти, поэтому этот метод никогда не вызывается». Итак, современный совет - не беспокоиться об этом и использовать dealloc.

Стивен Дарлингтон
источник
6
Также из документации: «Вы должны делать это только для объектов, которые вы можете легко воссоздать позже, либо в вашем методе viewDidLoad, либо из других частей вашего приложения. Вы не должны использовать этот метод для выпуска пользовательских данных или любой другой информации, которая не может быть легко воссоздается ». У меня тоже был этот вопрос, спасибо!
leolobato
Что делать, если вид в настоящее время виден? Разве не плохо было бы его уронить из-за предупреждения о нехватке памяти? ;) тогда приложение будет просто пустым. Я не понимаю смысла отпускать представление из-за нехватки памяти. Если я не вижу представления, я всегда освобождаю весь контроллер. Althogh у меня есть корневой контроллер представления, который остается нетронутым и управляет всей загрузкой / выгрузкой своих дочерних контроллеров представления ...
Спасибо
Нет, вы бы не использовали это, если бы просто поменяли одно представление другим. Подумайте о случае, когда у вас есть «стек» представлений с UINavigationController. Виден только один вид, и, если у вас есть предупреждение о памяти, вы можете отпустить все те, которые не видны.
Стивен Дарлингтон
Как вы контролируете, что viewDidUnload не вызывается в текущем видимом представлении, как было отмечено спасибо?
arielcamus 01
1
viewDidUnload не будет вызываться для текущего видимого представления, только для невидимых представлений.
progrmr
9

Это связано с тем, что вы обычно устанавливаете @propertyкак "(nonatomic, retain)"и как таковой сеттер, созданный для вас, освобождает текущий объект, а затем сохраняет аргумент, т.е.

self.property = nil;

... делает что-то вроде:

[property release];
property = [nil retain];

Следовательно, вы убиваете двух зайцев одним выстрелом: управление памятью (освобождение существующего объекта) и присвоение указателя значения nil (поскольку отправка любого сообщения на указатель nil вернет nil).

Надеюсь, это поможет.

gazzaaa87
источник
8

Помните, что viewDidUnloadэто метод в контроллере представления, а не в представлении. Метод представления dealloc будет вызван, когда представление выгружается, но метод контроллера представления dealloc может быть вызван позже.

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

Дэвид Мэймудес
источник
в этом есть смысл. Что произойдет, если я всегда отбрасываю весь контроллер представления? На самом деле я этим и занимаюсь. В этом случае мне не нужно много работать с -viewDidUnload, верно? У меня никогда не было ситуации, когда я отбрасываю только представление, так как я всегда отбрасываю весь контроллер, если он все равно не виден.
Спасибо
ну, просто помните, что в случае, когда ваше представление отображается, но у вас есть полноэкранный вид, такой как ImagePicker поверх него, ваше представление может быть выгружено, даже если вы не планировали его.
Дэвид Мэймудес
6

Вывод:

Контроллеры представления имеют свойство представления. Обычно перо или фрагмент кода добавляют к этому представлению другие представления. Это часто происходит внутри метода -viewDidLoad, например:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createManyViewsAndAddThemToSelfDotView];
}

кроме того, файл пера может создавать кнопку и добавлять ее к представлению контроллера представления.

В iPhone OS 2.2 при вызове -didReceiveMemoryWarning из системы вам нужно было что-то освободить, чтобы освободить память. Вы можете освободить представление всего контроллера представления, если это имело смысл. Или просто большое содержимое, занимающее много памяти.

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

Теперь в новой ОС 3.0 есть метод -viewDidUnload, который будет вызываться из системы, когда представление было выгружено из-за нехватки памяти (пожалуйста, поправьте меня: когда именно это будет вызвано?)

-viewDidUnload используется для освобождения всех объектов, которые принадлежали как самому контроллеру представления, так и представлению. Причина: если контроллер представления содержит ссылки на дочерние элементы представления, то есть кнопку, дочерние представления, на которые ссылаются, не будут освобождены, потому что их счетчик сохранения> = 1. После того, как они были освобождены в -viewDidUnload, они могут быть освобождены. из памяти.

Спасибо
источник
1
помнящий в поле зрения выгрузил, чтобы сделать self.button = nil ;, а не [отпускание кнопки] ;.
mk12
6

Apple не рекомендует использовать viewWillUnload, теперь вы должны использовать didReceiveMemoryWarning или dealloc для освобождения ваших объектов.

В iOS 6 методы viewWillUnload и viewDidUnload UIViewController теперь не рекомендуются. Если вы использовали эти методы для выпуска данных, используйте вместо этого метод didReceiveMemoryWarning. Вы также можете использовать этот метод для освобождения ссылок на представление контроллера представления, если оно не используется. Перед тем как это сделать, вам нужно будет проверить, находится ли представление не в окне.

Гильерме Торрес Кастро
источник
5

Если контроллер представления извлекается из стека контроллеров навигации и больше нигде не сохраняется, он будет освобожден, и вместо viewDidUnload будет вызываться dealloc. Вы должны освободить представления, созданные в loadView, в dealloc, но нет необходимости устанавливать для переменных значение nil, потому что вскоре после вызова dealloc переменные больше не будут существовать.

Колин
источник
3

Вы можете освободить любые подпредставления, за которые вы держитесь, например, тот UIImageView, который вы сохранили в своем методе loadView, или, еще лучше, изображение, которое было в этом UIImageView.

Drvdijk
источник