Коли я повинен випустити об'єкти в - (void) viewDidUnload, а не в -dealloc?


103

Для чого -(void)viewDidUnloadце добре?

Чи не можу я просто передати все -dealloc? Якщо вигляд не завантажився, -deallocйого все одно не називали б?

Відповіді:


51

На додаток до того, що вже було зазначено, я хотів детальніше зупинитися на логіці -viewDidUnload.

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

Додаткове право власності на підпогляди UIViewControllerозначає, що навіть коли його погляд буде видалено з ієрархії подання та звільнено для збереження пам’яті, завдяки якій субпрегляди також вивільняються поданням, вони фактично не будуть розміщені, оскільки UIViewControllerсам все ще містить власні видатні зберігаючи посилання на ці об’єкти. Вивільнення UIViewControllerдодаткового права власності на ці об'єкти гарантує, що вони будуть розміщені, а також звільнять пам'ять.

Об'єкти, які ви випускаєте тут, зазвичай відтворюються і встановлюються знову, коли UIViewControllerперегляд є re-loaded, або від Nib, або за допомогою реалізації -loadView.

Також зауважте, що UIViewController viewвластивість знаходиться nilдо моменту виклику цього методу.


1
Ви повинні прочитати developer.apple.com/library/ios/#featuredarticles/…, щоб зрозуміти життєвий цикл контролера подання / перегляду
Пол Солт

21

Як зазначено в документації :

Він викликається під час низької пам’яті, коли контролеру перегляду необхідно звільнити його перегляд та будь-які об’єкти, пов’язані з цим видом, щоб звільнити пам'ять.

У тій же ситуації , deallocце НЕ називається. Цей метод доступний лише в ОС3 та вище. Справа з такою ж ситуацією в iPhone OS 2.x справжній біль!

Оновлення липня 2015 року : Слід зазначити, що viewDidUnloadв iOS 6 було застаріло, оскільки "Перегляд більше не очищається в умовах низької пам'яті, і цей метод ніколи не застосовується". Отже, сучасна порада не турбуватися про це і користуватися dealloc.


6
Також з документів: "Ви повинні робити це лише для об'єктів, які ви зможете легко відтворити пізніше, або у вашому методі viewDidLoad, або в інших частинах програми. Ви не повинні використовувати цей метод для звільнення даних користувачів або будь-якої іншої інформації, яка не може бути легко відтворити ". Це питання у мене теж було, дякую!
leolobato

Що робити, якщо перегляд наразі видно? Не було б погано скинути його через низьке попередження пам’яті? ;) тоді додаток буде просто порожнім. Я не можу звільняти вигляд через низьку пам'ять. Якщо я не бачу виду, я завжди відпускаю весь контролер. У Althogh у мене є контролер кореневого виду, який залишається неушкодженим і керує всіма завантаженнями / розвантаженнями його контролерів дитячого перегляду ...
Дякую

Ні, ви б не використовували це, якщо просто поміняти один погляд на інший. Подумайте про випадок, коли у вас є "стек" переглядів за допомогою UINavigationController. Видно лише один вид, і якщо у вас є попередження про пам’ять, ви можете випустити всі, які не видно.
Стівен Дарлінгтон

Як ви керуєте тим, що viewDidUnload не викликається в поточному видимому вікні, як зауважив Спасибі?
arielcamus

1
viewDidUnload не буде викликано в поточному видимому вікні, лише на представленнях, які не видно.
progrmr

9

Це тому, що ви, як правило, встановлюєте @propertyяк "(nonatomic, retain)"і як такий сетер, який створений для вас, вивільняє поточний об'єкт, а потім зберігає аргумент, тобто

self.property = nil;

... робить щось відповідно до:

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

Тому ви вбиваєте двох птахів одним каменем: управління пам’яттю (звільнення існуючого об’єкта) та призначення покажчика до нуля (оскільки надсилання будь-якого повідомлення нульовому покажчику поверне нуль).

Сподіваюся, що це допомагає.


8

Пам’ятайте, що viewDidUnloadце метод у контролері перегляду, а не у поданні. Метод подання dealloc буде викликаний, коли вигляд завантажується, але метод контролера подання dealloc може бути викликаний не пізніше.

Якщо ви отримаєте попередження про низьку пам’ять, і ваш погляд не відображається, що відбудеться, наприклад, кожного разу, коли ви використовуєте UIImagePickerController, щоб користувач міг сфотографуватися, ваш погляд буде завантажений і після цього потрібно буде перезавантажитись.


що має сенс. Що станеться, якщо я завжди скидаю весь контролер перегляду? Це те, що я насправді роблю. У цьому випадку мені не доведеться багато мати справу з -viewDidUnload, правда? У мене ніколи не було ситуації, коли я опускав би лише вигляд, оскільки я завжди відкидаю весь контролер, якщо його все одно не видно.
Дякую

ну, просто пам’ятайте, що у випадку, коли ваш погляд відображається, але у вас є вид на повноекранному екрані, як ImagePicker, він може вивантажитись, навіть якщо ви цього не планували.
Девід Меймудс

6

Висновок:

Контролери перегляду мають властивість перегляду. Зазвичай нитка або фрагмент коду додають цьому виду інші види. Це трапляється часто в методі -viewDidLoad, як-от так:

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

крім того, файл nib може створити кнопку та додати її до подання контролера перегляду.

В 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
remeber з огляду зробив завантаження, щоб зробити self.button = nil ;, не [кнопку випуску] ;.
mk12

6

Apple застаріло viewWillUnload, тепер ви повинні використовувати didReceiveMemoryWarning або dealloc, щоб випустити ваші об'єкти.

В iOS 6 методи viewWillUnload та viewDidUnload UIViewController тепер застарілі. Якщо ви використовували ці методи для звільнення даних, використовуйте замість цього метод didReceiveMemoryWarning. Цей метод також можна використовувати для випуску посилань на вигляд контролера перегляду, якщо він не використовується. Вам потрібно буде перевірити, що перегляд не знаходиться у вікні, перш ніж це зробити.


5

Якщо контролер перегляду вискакує з стека контролера навігації і не зберігається більше ніде, він буде розміщений, і dealloc буде викликаний замість viewDidUnload. Ви повинні випустити представлення, створені в loadView в dealloc, але не потрібно встановлювати змінні на нуль, тому що незабаром після dealloc буде викликано змінних більше не буде.


3

Ви можете випустити будь-які підзагляди, на яких ви тримаєтесь, наприклад, UIImageView, який ви зберегли у вашому методі loadView, а ще краще зображення, яке було на тому UIImageView.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.