Потрібно зрозуміти життєвий цикл iOS UIViewController


299

Чи можете ви пояснити мені правильний спосіб управління UIViewControllerжиттєвим циклом?

Зокрема, я хотів би знати , як використовувати Initialize, ViewDidLoad, ViewWillAppear, ViewDidAppear, ViewWillDisappear, ViewDidDisappear, ViewDidUnloadі Disposeметоди в Mono Touch , для UIViewControllerкласу.


Чи є якась інформація або посилання для OSX ViewController і WindowController? Будь ласка, поділіться цим.
Ануп Вайдя

Відповіді:


410

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

Там здорово документація на сайті компанії Apple тут . Введення просто, хоча:

  • ViewDidLoad- Викликається під час створення класу та завантаження з xib. Відмінно підходить для початкового налаштування та одноразової роботи.

  • ViewWillAppear- Називається безпосередньо перед появою вашого перегляду, що добре для приховування / показу полів або будь-яких операцій, які ви хочете робити щоразу, перш ніж вид буде видно. Оскільки ви, можливо, будете повертатися вперед і назад між переглядами, це буде викликатися кожен раз, коли ваш погляд збирається з’являтися на екрані.

  • ViewDidAppear - Викликається після появи представлення - чудове місце для запуску анімації або завантаження зовнішніх даних з API.

  • ViewWillDisappear/ DidDisappear- Та сама ідея, що і ViewWillAppear/ ViewDidAppear.

  • ViewDidUnload/ ViewDidDispose- У Objective-C це місце, де ви займаєтеся очищенням та випуском матеріалів, але це обробляється автоматично, тому не так багато, що вам дійсно потрібно робити тут.


86
Цей текст злегка вводить в оману, оскільки ViewDidLoad не повинен використовуватися для одноразової роботи. Його можна викликати кілька разів, якщо вигляд буде завантажений через низьку пам'ять і знову завантажений.
Рікі Гельгессон

4
ViewDidLoad насправді не викликається під час створення / ініціалізації контролера перегляду. Це називається перший раз, коли ви робите що-небудь перегляд, пов'язаний із поданням контролера перегляду. Як і додати його як підвід, встановити кадр тощо. Це також називається під час завантаження з нибу.
Jason Grandelli

3
ViewDidAppear - Викликається після появи представлення - чудове місце для запуску анімації або завантаження зовнішніх даних з API. Чому це гарне місце для початку завантаження даних? Чому б не переглянутиDidLoad?
Антон Чикін

1
що з методом loadView, якщо він викликається вперше, коли ручка завантажується в пам'ять перед viewDidLoad чи ні.
iHulk

@chakrit, це хороший момент - viewDidAppear - це чудове місце для оновлення даних (якщо потрібно). Я не погоджуюся з приводу KVO, оскільки це може спричинити небажані оновлення поглядів, які ніколи насправді не переглядає користувач.
Антон Чикін

409

ОНОВЛЕННЯ: ViewDidUnload застаріло в iOS 6, тому відповідь оновлено відповідно.

Тут нанесено схему життєвого циклу UIViewController:

Життєвий цикл контролера подання, зафіксований на схемі

Перевага використання Xamarin Native / Mono Touch полягає в тому, що він використовує вбудовані API, і тому він дотримується того самого життєвого циклу ViewController, який ви знайдете в документації Apple.


17
Куди переглядають viewWillLayoutSubviews та viewDidLayoutSubviews на цій блок-схемі?
Max_Power89

7
Ця діаграма неточна. viewDidUnload є застарілим з iOS6: stackoverflow.com/questions/12509102 / ...
occulus

2
Це дійсно просто неправильно . Ще один приклад просто неправильної відповіді на ТА, як проходять роки. Обчислювальна техніка вкрай нестатична.
Fattie

186

Це для останніх версій iOS (модифіковано Xcode 9.3, Swift 4.1 ). Нижче наведені всі етапи, що робить життєвий цикл UIViewControllerзавершеним.

  • loadView()

  • loadViewIfNeeded()

  • viewDidLoad()

  • viewWillAppear(_ animated: Bool)

  • viewWillLayoutSubviews()

  • viewDidLayoutSubviews()

  • viewDidAppear(_ animated: Bool)

  • viewWillDisappear(_ animated: Bool)

  • viewDidDisappear(_ animated: Bool)

Дозвольте пояснити всі ці етапи.

1. loadView

Ця подія створює / завантажує представлення, яким керує контролер. Він може завантажуватися із пов'язаного файлу nib або порожнього, UIViewякщо нуль знайдено. Це робить його гарним місцем для створення ваших поглядів у коді програмно.

Тут підкласи повинні створювати власну ієрархію подання, якщо вони не використовують нитку. Ніколи не слід телефонувати безпосередньо. Тільки перевизначити цей метод , коли ви програмно створити уявлення і призначити вид кореня до viewвласності не називати супер метод , коли ви перевизначити loadView

2. loadViewIfNeeded

Якщо обкладинка поточного перегляду viewControllerще не встановлена, цей метод завантажить подання, але пам’ятайте, що це доступно лише в iOS> = 9.0. Тож якщо ви підтримуєте iOS <9.0, тоді не сподівайтеся, що він з’явиться у зображенні.

Завантажує подання контролера перегляду, якщо воно ще не встановлено.

3. viewDidLoad

viewDidLoadПодія викликається тільки тоді , коли вид створюється і завантажується в пам'ять , але кордону для подання ще не визначені. Це гарне місце для ініціалізації об'єктів, які збирається використовувати контролер перегляду.

Викликається після завантаження перегляду. Для контролерів перегляду, створених у коді, це після -loadView. Для контролерів перегляду, не дозволених від ручки, це відбувається після встановлення подання.

4. viewWillAppear

Ця подія сповіщає viewControllerкожного разу, коли подання відображається на екрані. На цьому етапі подання має межі, які визначені, але орієнтація не встановлена.

Викликається, коли подання стане видимим. За замовчуванням нічого не робить.

5. viewWillLayoutSubviews

Це перший крок у життєвому циклі, де межі доопрацьовуються. Якщо ви не використовуєте обмежень або автоматичного макета, ви, ймовірно, хочете оновити тут підперегляди. Це доступно лише в iOS> = 5.0. Тож якщо ви підтримуєте iOS <5.0, то не сподівайтесь, що він відобразиться.

Викликається безпосередньо перед тим, як викликається макет подання диспетчера перегляду. Підкласи можуть реалізовуватись за необхідності. За замовчуванням - nop.

6. viewDidLayoutSubviews

Ця подія сповіщає контролер перегляду, що підгляди були налаштовані. Це гарне місце, щоб внести будь-які зміни в підперегляди після їх встановлення. Це доступно лише в iOS> = 5.0. Тож якщо ви підтримуєте iOS <5.0, то не сподівайтесь, що він відобразиться.

Викликається одразу після виклику методу компонування виду контролера перегляду. Підкласи можуть реалізовуватись за необхідності. За замовчуванням - nop.

7. viewDidAppear

На viewDidAppearподію спрацьовує після подання представлений на екрані. Що робить його гарним місцем для отримання даних із сервісу резервної копії чи бази даних.

Викликається, коли погляд повністю переведений на екран. За замовчуванням нічого не робить

8. viewWillDisappear

У viewWillDisappearподія спрацьовує , коли вид представлений viewControllerось - ось зникне, вибачте, кришку або сховатися за одною viewController. Це хороше місце, де ви можете обмежувати мережеві дзвінки, недійсним таймером або випускати об'єкти, які пов'язані з цим viewController.

Викликається, коли подання відхилено, прикрито або приховано іншим чином.

9. viewDidDisappear

Це останній крок життєвого циклу, до якого може звернутися будь-хто, коли ця подія стартує одразу після того, як вигляд представлених viewControllerзник, звільнений, охоплений або прихований.

Викликається після відхилення, закриття чи приховання іншим способом. За замовчуванням нічого не робить

Тепер, як в Apple, коли ви реалізуєте цей метод, ви повинні пам'ятати, щоб викликати superреалізацію цього конкретного методу.

Якщо ви підклас UIViewController, ви повинні викликати суперреалізацію цього методу, навіть якщо ви не використовуєте NIB. (Для зручності метод init за замовчуванням зробить це для вас і вкажіть нуль для обох аргументів цього методу.) У вказаному NIB проксі-власнику файлу повинен бути встановлений клас для підкласу контролера перегляду, з розеткою перегляду підключено до головного виду. Якщо ви посилаєтесь на цей метод з ім'ям nil nib, то -loadViewметод цього класу намагатиметься завантажити NIB, ім'я якого збігається з класом вашого контролера перегляду. Якщо такого NIB насправді не існує, вам потрібно або зателефонувати, -setView:перш ніж -viewвикликати його, або замінити -loadViewметод програмного налаштування своїх поглядів.

Сподіваюся, що це допомогло. Дякую.

ОНОВЛЕННЯ - Як @ThomasW вказував всередині коментаря, viewWillLayoutSubviewsа viewDidLayoutSubviewsтакож буде викликатися в інші часи, коли завантажуються підгляди основного виду, наприклад, коли завантажуються комірки подання таблиці або виду колекції.

ОНОВЛЕННЯ - Як @Maria вказав у коментарі, опис loadViewбуло оновлено


6
viewWillLayoutSubviewsа viewDidLayoutSubviewsтакож буде викликано в інші часи, коли завантажуються підгляди основного виду, наприклад, коли завантажуються комірки подання таблиці або представлення колекції.
ThomasW

У цій відповіді є незначне введення в оману: loadView () завжди викликається, його просто не слід перекривати при перегляді контролера, створеного в ІБ.
Марія

@Maria Будь ласка, продовжуйте та відредагуйте відповідь, якщо ви думаєте, що її можна покращити. Дякую.
onCompletion

За замовчуванням нічого поганого немає viewWillAppear viewDidAppear viewDidDisappear. Ви повинні зателефонувати супер в якийсь момент.
Мік

47

iOS 10,11 (Swift 3.1, Swift 4.0)

За словами UIViewControllerв UIKitрозробників,

1. loadView ()

Тут підкласи повинні створювати власну ієрархію подання, якщо вони не використовують нитку . Ніколи не слід телефонувати безпосередньо.

2. loadViewIfNeeded ()

Завантажує подання контролера перегляду, якщо воно ще не встановлено.

3. viewDidLoad ()

Викликається після завантаження перегляду. Для контролерів перегляду, створених у коді, це після -loadView. Для контролерів перегляду, не дозволених від ручки, це відбувається після встановлення подання.

4. viewWillAppear (_ анімований: Bool)

Викликається, коли подання стане видимим. За замовчуванням нічого не робить

5. viewWillLayoutSubviews ()

Викликається безпосередньо перед тим, як викликається макет подання диспетчера перегляду. Підкласи можуть реалізовуватись за необхідності. За замовчуванням нічого не робить.

6. viewDidLayoutSubviews ()

Викликається одразу після виклику методу компонування виду контролера перегляду. Підкласи можуть реалізовуватись за необхідності. За замовчуванням нічого не робить.

7. viewDidAppear (_ анімований: Bool)

Викликається, коли погляд повністю переведений на екран. За замовчуванням нічого не робить

8. viewWillDisappear (_ анімований: Bool)

Викликається, коли подання відхилено, прикрито або приховано іншим чином. За замовчуванням нічого не робить

9. viewDidDisappear (_ анімований: Bool )

Викликається після відхилення, закриття чи приховання іншим способом. За замовчуванням нічого не робить

10. viewWillTransition (до розміру: CGSize, з координатором: UIViewControllerTransitionCoordinator)

Викликається, коли перегляд переходить.

11. willMove (батько toParentViewController: UIViewController?)

12. didMove (батько toParentViewController: UIViewController?)

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

Батьківський аргумент в обох цих методах є нульовим, коли дитину віддаляють від батьків; інакше він дорівнює новому батьківському контролеру подання.

13. didReceiveMemoryWarning ()

Викликається, коли батьківська програма отримує попередження про пам'ять. На iOS 6.0 він більше не очищає перегляд за замовчуванням.


2
Насправді дуже складно, що stackoverflow не очистить усі помилкові та неповні відповіді з усієї теми. Ваша відповідь здається повною, що стосується викликів методів, тож я вважаю, що ваша правильна і я працюю з цим.
Logicsaurus Rex

Що таке, nibяк згадувалося нижче loadView?
Петрус Терон

2
@LogicsaurusRex Я згоден. Точно так само, як SO позначає питання як дублікати або захищені, я думаю, що він повинен мати можливість позначати відповіді як застарілі або застарілі
rmp251

Пункт 5 вище - неправильний. viewWillLayoutSubviews()викликається до того, як об’єкт перегляду ViewController посилається на його layoutSubviews()метод
williamukoh

28

Станом на iOS 6 і далі. Нова схема така:

введіть тут опис зображення


1
Назвіть цей вид "А". Розглянемо другий вигляд "B", який з'являється під час зникнення "A". Чи "B.viewWillAppear" до або після "A.viewDidDisappear"? І чи існують ситуації, коли порядок цих двох змінюється?
ToolmakerSteve

Здається, що буде показано, що "B" буде показано, перш ніж з'явиться. Для другого питання. Потрібно трохи часу, щоб розглянути це.
Саад

21

Давайте зосередимось на методах, які відповідають за життєвий цикл UIViewController :

  • Створення:

    - (void)init

    - (void)initWithNibName:

  • Переглянути створення:

    - (BOOL)isViewLoaded

    - (void)loadView

    - (void)viewDidLoad

    - (UIView *)initWithFrame:(CGRect)frame

    - (UIView *)initWithCoder:(NSCoder *)coder

  • Поводження із зміною стану перегляду:

    - (void)viewDidLoad

    - (void)viewWillAppear:(BOOL)animated

    - (void)viewDidAppear:(BOOL)animated

    - (void)viewWillDisappear:(BOOL)animated

    - (void)viewDidDisappear:(BOOL)animated

    - (void)viewDidUnload

  • Попередження щодо пам'яті:

    - (void)didReceiveMemoryWarning

  • Розміщення

    - (void)viewDidUnload

    - (void)dealloc

Схема життєвого циклу UIViewController

Для отримання додаткової інформації ознайомтесь із посиланням на клас UIViewController .


19

Методи viewWillLayoutSubviewsі viewDidLayoutSubviewsна діаграмах не згадуються, але вони називаються між viewWillAppearі viewDidAppear. Їх можна назвати кілька разів.


Вони також будуть викликатися в інші часи, коли завантажуються підгляди основного представлення даних, наприклад, коли завантажуються комірки подання таблиці або представлення колекції.
ThomasW

16

Відповідь Хайдера є правильною для попередньої iOS 6. Однак станом на iOS 6 viewDidUnload та viewWillUnload ніколи не викликаються. Документи стан: «Перегляди паче не продуває в умовах низької пам'яті і тому цей метод ніколи не викликається.»


Я спробував поставити точку перерви в ViewWillDisappear, ViewDidDisappear, Dispose. Але жоден з них не викликав, коли я переходив методом PresentViewController (). Що може бути причиною?
Sreeraj

1
Посилання не працює ... Отже, що робить ОС в умовах недостатньої пам’яті?
Син

Зберігає їх на диску?
Ian Warburton

16

Тут багато застарілої та неповної інформації. Лише для iOS 6 та новіших версій :

  1. loadView[a]
  2. viewDidLoad[a]
  3. viewWillAppear
  4. viewWillLayoutSubviews вперше встановлено межі
  5. viewDidLayoutSubviews
  6. viewDidAppear
  7. * viewWillLayoutSubviews[b]
  8. * viewDidLayoutSubviews[b]

Виноски:

(а) - Якщо ви вручну скасуєте свій перегляд під час didReceiveMemoryWarning, loadViewі viewDidLoadвін буде викликаний знову. Тобто за замовчуванням loadViewі viewDidLoadвикликається лише один раз за екземпляр контролера перегляду.

(b) Може називатися додатково 0 або більше разів.


1
viewWillLayoutSubviewsа viewDidLayoutSubviewsтакож буде викликано в інші часи, коли завантажуються підгляди основного виду, наприклад, коли завантажуються комірки подання таблиці або представлення колекції.
ThomasW

11

Пояснення переходів держави в офіційному документі: https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/index.html

На цьому зображенні показані дійсні переходи стану між різними методами зворотного виклику виду "воля" та "зробив"

Дійсні державні переходи:


Взято з: https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Art/UIViewController Class Reference_2x.png


0

Відповідно до документа Apple - Почніть розробляти програми для iOS (Swift) - Робота з контролерами перегляду - Розуміння життєвого циклу контролера подання

viewDidLoad()—Викликається, коли створений і завантажений з дошки розкадрівку вміст подання контролера перегляду (у верхній частині його ієрархії подання). … Використовуйте цей метод для виконання будь-яких додаткових налаштувань, необхідних контролеру перегляду.

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

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

viewWillDisappear()—Викликається безпосередньо перед тим, як видалити вміст диспетчера перегляду з ієрархії подання програм. Використовуйте цей метод для виконання завдань очищення, таких як внесення змін або відставка статусу першого відповіді.

viewDidDisappear()—Викликається одразу після того, як вигляд вмісту контролера перегляду видалено з ієрархії подання програм. Використовуйте цей метод для виконання додаткових заходів, що розкриваються.

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