Жизненный цикл UIViewController - Код Воробья
Интерфейс в UIKit

Жизненный цикл UIViewController

Рассмотрим когда вызываются методы контроллера и что можно делать внутри них. Когда настраивать вьюхи и данные.

developer.apple.com

Имя Автора
Автор Иван Воробей iOS разработчик. Пишу библиотеки, веду телеграм-канал.

В этой статье рассмотрим жизненный цикл ViewController'a. Посмотрим когда вызываются методы и что можно делать внутри них. Так же рассмотрим частые ошибки.

Начнем с UIView. Он ведет себя предсказуемо, как только вызвали инициализатор - выделяется память. Теперь проперти имеют значения и объект можно использовать.

У контроллера есть вью. Но то, что контроллер создан, не означает что вью создана тоже. Система ждет повод создать её. Концепция жизненного цикла строится вокруг этой особенности. Просто держите в уме, что вью создается по необходимости.

Инициализируем

Рассмотрим базовый UIViewController, инициализаторов два:

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
    
required init?(coder: NSCoder) {
    super.init(coder: coder)
}

Ещё есть инициализатор без параметров init(), но это обертка над первым иницициализатором.

На этом этапе контроллер ведет себя как обычный класс: инициализирует проперти, отрабатывает тело инициализатора. Контроллер может быть долго в состоянии без загруженной вью, а может даже никогда не загрузить ее. Вью загрузится как только система или разработчик обратится к проперти .view.

Загружаем

Разработчик презентует контроллер. Для системы это повод загрузить вью - выделяется память. Мы можем следить за процессом и даже вмешаться. Глянем какие методы доступны:

override func loadView() {
    super.loadView()
}

Метод loadView() вызывается системой. Его не нужно вызывать вручную, но можно переопределить, чтобы подменить корневую вью. Если нужно загрузить вью вручную (и вы знаете что делаете), то держите красную кнопку loadViewIfNeeded().

Второй метод легендарен, как Стив Джобс. Он вызывается когда вью закончила загрузку.

override viewDidLoad() {
    super.viewDidLoad()
}

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

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

Раньше я делал проперти-вьюхи контроллера просто создавая их:

class ViewController: UIViewController {
    
    var redView = UIView()
}

Проперти инициализируется вместе с контроллером, а значит память для вью выделится сразу. Чтобы отложить это до требования, нужно пометить проперти как lazy.

В методе viewDidLoad() размеры вьюхи неверные, привязываться к высоте и ширине нельзя. Делайте настройку, которая не зависят от размеров.

Хочу остановиться на viewDidUnload(). Корневая вью может выгружаться из памяти, а это означает кое-что невероятное:

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

Не нужно срочно брать внеурочные и все выходные переделывать вашу VPN-ку. Ничего не сломается, viewDidLoad() редко вызывается несколько раз. Держите в уме, что нужно разнести настройку данных и вьюх в следующем проекте.

Показываем

Появление контроллера начинается с метода viewWillAppear:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
}
    
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
}

Оба метода в связке. Тут делать настройку не нужно, но можно спрятать/показать вьюхи или добавить несложное поведение. В методе viewDidAppear() начинайте сетевой запрос или крутите индикатор загрузки. Оба метода могут вызываться несколько раз.

Есть методы, которые сообщают что вью пропадает с экрана. Наглядная схема:

ViewController LifeCycle

Обратите внимание на пару антагонистов viewWillDisappear() и viewDidDisappear. Они вызываются, когда вью удаляется из иерархии представлений. Если вы показываете другой контроллер поверх, то методы не вызываются.

Layout

Методы лейаута, аналогично методам выше, подвязаны к жизненному циклу вьюхи. Доступно 3 метода:

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
}
    
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
}

Первый метод вызывается до layoutSubviews() корневой вью, второй - после. Во втором методе размеры корректные, а вью размещены правильно - можно подвязываться к размерам корневой вью.

Есть отдельный метод про изменение размеров вью. Это не обязательно поворот устройства, хотя он тоже:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
}

После будут вызваны методы viewWillLayoutSubviews() и viewDidLayoutSubviews().

Кончается память

Вызывается, если память переполняется. Если вы не очистите объекты, из-за которых это происходит, iOS принудительно выключит приложение (для пользователя будет выглядеть как краш).

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

На этом всё. Жизненный цикл контроллера большая тема, я мог что-то упустить. Дайте мне знать если нашли что-то или есть хороший пример для статьи.


Другие туториалы

Часть 1: Коллекция и Таблица

Drag и Drop

Как изменить порядок ячеек в коллекции и таблице. Как перенести ячейки в другую коллекцию. Перемещение нескольких ячеек группой.

Новое в iOS 15

UISheetPresentationController

В iOS 15 появились sheet-контроллеры. Их можно перетаскивать с изменением высоты. Вы встречали эти контроллеры в приложениях «Карты» и «Акции».

Новое в iOS 15

StoreKit 2

Apple пересмотрела логику покупок и переписала StoreKit. Буду много хвалить - крутой апдейт этого года.

Подборка

Ресурсы для iOS разработчиков

Подборка полезных ссылок для iOS разработчиков. Структурирована по формату материала. Есть раздел с русскими ресурсами.

В telegram-канале приходят уведомления о новых туториалах. В чате для iOS разработчиков ответят на вопросы.

Открыть Telegram-канал