Ответ
Жизненный цикл UIViewController — это последовательность системных вызовов, управляющих созданием, отображением и уничтожением контроллера и его view.
Основные этапы и методы:
-
Инициализация и загрузка View:
init(coder:)/init(nibName:bundle:)– создание экземпляра контроллера.loadView()– создает или загружает иерархию view. Переопределяйте, если создаете view вручную.viewDidLoad()– Вызывается один раз после загрузки view. Идеальное место для начальной настройки UI.
-
Появление на экране:
viewWillAppear(_:)– Вызывается перед тем, как view станет видимой. Хорошее место для обновления данных или анимаций, зависящих от контекста.viewDidAppear(_:)– Вызывается после того, как view появилась на экране. Место для запуска тяжелых операций (например, сетевых запросов) или анимаций.
-
Исчезновение с экрана:
viewWillDisappear(_:)– Вызывается перед скрытием view. Место для сохранения состояния или отмены изменений.viewDidDisappear(_:)– Вызывается после того, как view скрылась.
-
Изменение layout (разметки):
viewWillLayoutSubviews()– Вызывается передlayoutSubviewsу корневой view.viewDidLayoutSubviews()– Вызывается после. Идеально для корректировки layout после расчета системой Auto Layout.
-
Управление памятью и деинициализация:
didReceiveMemoryWarning()– Уведомление о нехватке памяти.deinit– Вызывается перед освобождением контроллера из памяти.
Практический пример использования:
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Разовая настройка: добавить subviews, настроить навигацию.
setupTableView()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Обновить данные каждый раз при появлении.
tableView.reloadData()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Скорректировать frame после Auto Layout.
customView.layer.cornerRadius = customView.bounds.width / 2
}
} Ответ 18+ 🔞
А, жизненный цикл UIViewController! Ну это же классика, блядь, как "Муму" у Тургенева, только про вьюхи. Сейчас разжуём, что за хуйня тут происходит, а то народ путается, как Герасим немой в анекдотах.
Смотри, представь, что твой контроллер — это такой актёр на сцене. Система — режиссёр-садист, который его то выводит на сцену, то за кулисы прогоняет, а потом и вовсе нахуй вышвыривает. И у каждого действия есть свой звонок, свой метод, куда можно вписаться и своё говно подкинуть.
Основные этапы, или "От зачатия до пиздеца":
-
Рождение и сборка декораций:
init(coder:)/init(nibName:bundle:)– это типа тест на беременность и УЗИ. Контроллер только-только создали, а вьюхи ещё нихуя нет. Как Герасима только привезли в усадьбу.loadView()– а вот тут уже строят сарай, где он будет жить. Ты можешь сам сколотить этот сарай из досок (UIView()), если хочешь. Но обычно не лезешь, система сама загрузит из сториборда или xib.viewDidLoad()– О, это святое! Вызывается один раз, когда сарай построен, но ещё не открыли дверь. Все стены стоят, окна есть. Идеальное место, чтобы расставить мебель (добавить сабвью), повесить картину (navigationItem.title) и сказать "Муму" в первый раз. Разовая настройка, блядь!
-
Выход на сцену (появление на экране):
viewWillAppear(_:)– Занавес вот-вот откроется, актёр уже в кулисе. Хороший момент, чтобы прочистить горло (обновить данные в таблице), потому что зрители (пользователи) уже сидят.viewDidAppear(_:)– Занавес открылся, тебя все видят, свет софитов бьёт в глаза. Можно начинать свой трёхчасовой монолог (запускать анимации, тянуть данные с сервера). Но если монолог будет скучный, зрители заснут (интерфейс зависнет).
-
Уход за кулисы (исчезновение):
viewWillDisappear(_:)– Тебе уже машут из-за кулис: "Кончай, уёбок, следующий номер!". Пора закругляться: сохранить, в каком абзаце остановился (состояние), или отменить танец с бубном (инвалидацию таймеров).viewDidDisappear(_:)– Занавес закрылся, тебя уже не видно. Можно переодеться, выдохнуть и пойти бухнуть. Контроллер ещё жив, но на сцене его нет.
-
Перестановка мебели (изменение layout'а):
viewWillLayoutSubviews()/viewDidLayoutSubviews()– Это когда режиссёр пришёл и говорит: "А давайте диван не тут поставим, а повернём телефон". Автолейаут только что посчитал все фреймы. ВdidLayout— идеальный момент, чтобы скруглить углы у вьюхи, потому что её размеры теперь точно известны. Делать это вviewDidLoad— рано, там размеры могут быть ещё ебейшие!
-
Смерть и расправа над памятью:
didReceiveMemoryWarning()– Система орёт: "У нас памяти на всех не хватает, блядь! Кто не нужен — нахуй!". Надо срочно выкинуть кэш картинок или тяжёлые данные, иначе тебя самого выкинут.deinit– Финальная сцена. Контроллера уже нет, он как Муму на дне пруда. Вызывается, когда на него не осталось сильных ссылок. Место, чтобы отписаться от нотификаций и сказать "Прощай, жопа с ручками!".
Ну и пример, чтобы не быть пиздаболом:
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Разово строим сцену. Добавили стол, стул, поставили собачью миску.
setupTableView() // Типа, собрали таблицу из IKEA
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Каждый раз перед выходом вытираем пыль и кладём свежие газеты.
tableView.reloadData() // Обновляем данные, а то там вчерашние новости
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Автолейаут всё расставил, теперь можно картину криво повесить.
// А точнее — сделать вьюху круглой, потому что её bounds теперь точные.
customView.layer.cornerRadius = customView.bounds.width / 2
}
}
Вот и вся магия, ёпта. Главное — не пытаться в viewDidLoad работать с размерами, которые ещё не рассчитаны, а то получишь квадратное круглое и будешь потом, как Герасим, мычать "Муму" от безысходности. И помни про память, а то система тебя, как ту самую собаку, без церемоний утопит.