Как происходит рождение UIViewController (какой метод следует за каким)? - PullRequest
57 голосов
/ 24 февраля 2011

Есть много методов для переопределения, например initWithNibname:, awakeFromNib, loadView, viewDidLoad, viewDidAppear:, layoutSubviews, и я просто не могу решить, в каком порядке эти методы будут вызываться.

Я просто переопределяю один из них "наизусть".

Есть подробные объяснения?

Ответы [ 7 ]

173 голосов
/ 24 февраля 2011

За кулисами происходит очень многое с Представление какао и управление ViewController .

1.Объект viewController

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

UIViewController * myVC = [[UIViewController alloc] initWith...];
...
[myVC release];

Назначенный инициализатор для viewControllers - -initWithNibname:bundle:.Если вы укажете перо, viewController может автоматически загрузить свое представление из этого кончика и подключить любые IBOutlets, которые вы определили (более подробно см. Ниже).

2.Загрузка и выгрузка представления

ViewController загрузит его представление по мере необходимости.Это обычно происходит, когда метод -view вызывается впервые, и может произойти в любой момент в вашей программе, в зависимости от того, как вы инициализируете свой пользовательский интерфейс.Представление также может быть уничтожено и перезагружено несколько раз в течение жизни вашей программы, даже в зависимости от того, как вы управляете своим пользовательским интерфейсом.Когда viewController определил, что его представление требуется, но еще не загружено, будет вызван метод -loadView.Основной поток сообщений выглядит примерно так:

view
  loadView
  viewDidLoad

Обратите внимание, что если вы переопределите метод -view, -loadView и viewDidLoad не будут вызываться автоматически.Если вы переопределите -loadView, вы должны установить свойство view viewController.В противном случае следующий вызов -view снова запустит процесс загрузки.

Представление также может быть выгружено в любое время в течение жизненного цикла вашей программы, просто установив для свойства view значение nil.Реализация по умолчанию -didReceiveMemoryWarning сделает это автоматически, если представление не имеет суперпредставления (т.е. если оно не является частью иерархии активного представления).Поток сообщений выглядит следующим образом:

view = nil
   viewDidUnload

2a.Загрузка представления программным способом

Если вы решите переопределить -loadView, вы можете создавать представления, подпредставления, другие viewControllers и любые соединения между этими объектами любым удобным для вас способом.Конечно, это означает, что вы также несете ответственность за управление памятью в отношении объектов, которые вы создаете.Если ваш подкласс переопределяет -loadView, он должен быть инициализирован с использованием nil для nibName и bundle.

2b.Загрузка представления из пера

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

С nib-файлами дела обстоят немного сложнее, поскольку за кулисами происходит так много всего.Метод -awakeFromNib вызывается для каждого объекта , который создается при загрузке файла пера, и нет никакой гарантии, что другие объекты в файле пера будут полностью загружены при его вызове.

3.Отображение представлений

-viewWillAppear:, -viewDidAppear:, -viewWillDisappear: и -viewDidDisappear: вызывается только тогда, когда представление отображается или скрывается на экране, особенно во время анимированных переходов из одного вида в другой.,Эти методы могут вызываться много раз в течение жизненного цикла вашей программы, так как представления меняются местами в вашей схеме навигации.

4.Посмотреть макет

Метод -layoutSubviews является , а не частью UIViewController.Он вызывается для UIView объектов, когда их границы были изменены.Если в вашей программе используется пользовательский подкласс UIView, этот метод можно использовать для создания пользовательского макета подпредставления вместо использования стандартных методов автоматического изменения размера Cocoa.

5.Собираем все вместе

Из-за сложности есть много разных способов для этого процесса, но нормальная временная шкала может выглядеть примерно так:

-[viewController initWithNibname:Bundle:]
-[viewController awakeFromNib]
-[viewController loadView]
-[view awakeFromNib]
-[viewController viewDidLoad]
-[viewController viewWillAppear]
-[viewController viewDidAppear]
...
-[viewController viewWillDisappear]  // user navigated away
-[viewController viewDidDisappear]
...
-[viewController viewWillAppear]     // user navigated back
-[viewController viewDidAppear]
...
-[viewController viewWillDisappear]  // user navigated away
-[viewController viewDidDisappear]
...
-[viewController setView:nil]        // memory warning, perhaps
-[viewController viewDidUnload]
...
-[viewController loadView]           // user navigated back
-[view awakeFromNib]
-[viewController viewDidLoad]
-[viewController viewWillAppear]
-[viewController viewDidAppear]
...
36 голосов
/ 05 февраля 2014

Я недавно пересмотрел это и создал тестовый проект: https://github.com/Janek2004/ViewControllerTest

Запустите проект на симуляторе iOS, чтобы увидеть порядок выполнения методов подкласса UIViewController.Порядок может отличаться всякий раз, когда мы используем файл Nib вместо раскадровки или контроллера представления загрузки программно.

  1. - [ViewController initWithCoder:] Разархивировать данные из кончика или раскадровки
  2. - [ViewController awakeFromNib] Подготавливает приемник к обслуживанию после его загрузки из архива Interface Builder или файла пера.
  3. - [ViewController loadView] Вы никогда не должны вызывать этот метод напрямую.Контроллер представления вызывает этот метод, когда запрашивается его свойство view, но в данный момент оно равно nil.Этот метод загружает или создает представление и назначает его свойству представления.
  4. - [ViewController viewDidLoad] Этот метод вызывается после того, как контроллер представления загрузил свою иерархию представления в память.
  5. - [ViewController viewWillAppear:] Этот метод вызывается до того, как представление получателя собирается добавить в иерархию представления, и до того, как настроены какие-либо анимации для отображения представления.
  6. - [ViewController viewWillLayoutSubviews] Вызывается, чтобы уведомить контроллер представления о том, что его представление собирается расположить свои подпредставления. Когда изменяются границы представления, представление корректирует положение своих подпредставлений.Ваш контроллер представления может переопределить этот метод, чтобы внести изменения, прежде чем представление раскладывает свои подпредставления.
  7. - [ViewController viewDidLayoutSubviews] Вызывается для уведомления контроллера представления о том, что его представление только что разложило свои подпредставления.Когда границы изменяются для представления контроллера представления, представление регулирует положения его подпредставлений, и затем система вызывает этот метод.Однако этот вызываемый метод не означает, что отдельные макеты подпредставлений представления были скорректированы.Каждое подпредставление отвечает за настройку своего макета.
  8. - [ViewController viewDidAppear:] Уведомляет контроллер представления о том, что его представление было добавлено в иерархию представления.Вы можете переопределить этот метод для выполнения дополнительных задач, связанных с представлением представления.

  9. - [ViewController viewWillDisappear:] Уведомляет контроллер представления о том, что его представление собирается бытьудалено из иерархии представлений. Этот метод вызывается в ответ на удаление представления из иерархии представлений.Этот метод вызывается до того, как представление фактически будет удалено, и до того, как настроены какие-либо анимации.Уведомляет контроллер представления, что его представление было добавлено к иерархии представления.Вы можете переопределить этот метод для выполнения дополнительных задач, связанных с представлением представления.

  10. - [ViewController viewDidDisappear:] Уведомляет контроллер представления о том, что его представление было удалено из иерархии представления.
9 голосов
/ 22 ноября 2014

Еще один ключевой момент в этом процессе - это когда layoutSubviews вызывается для любых подпредставлений.Именно в этот момент, и не раньше, будут применены любые ограничения, настроенные в раскадровке.Если вам нужно внести какие-либо корректировки в подпредставления представления, основываясь на его ограниченных координатах, вы должны сделать это в layoutSubviews.Если вы сделаете это в viewDidLayoutSubviews, это будет слишком скоро, поскольку к этим подпредставлениям еще не применены свои ограничения (потому что, как сказано в документации, «каждое подпредставление отвечает за настройку своего собственного макета».) И если вы делаете это в viewDidAppear,очевидно, это будет слишком поздно, так как пользователь увидит, как ваши подпредставления меняют координаты.Итак, другой жизненно важный шаг в этом процессе:

-viewController viewWillAppear
-viewController viewWillLayoutSubviews
-viewController viewDidLayoutSubviews
---> viewController.[any subview] layoutSubviews
-viewController viewDidAppear  
4 голосов
/ 24 февраля 2011

из документации Apple UIViewController:

Когда вы определяете новый подкласс UIViewController, вы должны указать представления, которые будут управляться контроллером.Существует два взаимоисключающих способа указать эти представления: вручную или с помощью файла пера.Если вы задаете представления вручную, вы должны реализовать метод loadView и использовать его для назначения корневого объекта представления свойству представления.Если вы задаете представления с помощью файла пера, вы не должны переопределять loadView, а должны вместо этого создать файл пера в Интерфейсном Разработчике, а затем инициализировать свой объект контроллера представления, используя initWithNibName: bundle: метод.Создание представлений с использованием файла пера часто проще, поскольку вы можете использовать приложение Interface Builder для графического создания и настройки ваших представлений (в отличие от программного).Однако оба метода имеют один и тот же конечный результат, который заключается в создании соответствующего набора представлений и представлении их через свойство представления.

От макушки головы:

  1. initWithNibname
  2. loadView (загрузка материала вручную)
  3. viewDidiLoad
  4. viewDidAppear

без подсказки, куда входит layoutSubviews

1 голос
/ 21 ноября 2013
-- This is related to view only:
-viewWillAppear:
-viewDidAppear: 
-viewWillDisappear: and 
-viewDidDisappear: 

are only called when the view is being displayed.

-viewController viewDidLoad
-viewController viewWillAppear
-viewController viewDidAppear

other methods

-viewController viewDidDisappear
-viewController viewWillDisappear 
-viewController viewDidUnload
1 голос
/ 24 февраля 2011

Обычно я решаю этот вопрос, помещая NSLog (или точки останова) во все эти делегаты, включая делегат запуска приложения, и следуя порядку в отладчике.

0 голосов
/ 04 мая 2013

Я хочу поблагодарить e.James за его превосходное описание.Я пока не могу комментировать сообщение, но для быстрой визуальной иллюстрации см. эту блок-схему в руководстве по программированию View Controller.И я понимаю, что это не по теме, но для графика последовательности запуска приложения обратитесь к Руководству по программированию приложений iOS.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...