> Какой жизненный цикл у UIViewController и в каком порядке вызываются методы (iOS, Swift)

Уровень: senior · Роль: mobile · Категория: Технические вопросы

Компании: VK, Физтех-Центр, Bip.ru, Doubletapp, Битрикс24, Совкомбанк, Яндекс

Стек: iOS, Swift

> Пример ответа

Короткий ответ

Жизненный цикл UIViewController - это последовательность вызовов методов, отражающих переходы между состояниями: загрузка view, появление на экране, исчезновение, освобождение памяти. Основной порядок: loadViewviewDidLoadviewWillAppearviewDidAppearviewWillDisappearviewDidDisappear. При нехватке памяти вызывается didReceiveMemoryWarning. Методы вызываются в строгом порядке, но некоторые могут повторяться при повторном появлении контроллера.

Подробное объяснение

Жизненный цикл делится на две фазы: создание и отображение view, а также управление памятью.

Фаза создания view:

  • loadView - создаёт корневую view контроллера. Вызывается один раз при первом обращении к view. Если переопределён, нужно создать view вручную и присвоить в self.view. Если не переопределён, загружается из storyboard/xib или создаётся пустая UIView.
  • viewDidLoad - вызывается сразу после загрузки view в память. Здесь выполняют начальную настройку: конфигурация UI-элементов, подписки, начальные данные. Вызывается один раз за время жизни контроллера.

Фаза появления/исчезновения:

  • viewWillAppear(_:) - вызывается перед добавлением view в иерархию окон. Используется для обновления данных, скрытия/показа элементов, настройки navigation bar.
  • viewDidAppear(_:) - вызывается после полного отображения view на экране. Подходит для запуска анимаций, аналитики, тяжёлых операций.
  • viewWillDisappear(_:) - вызывается перед удалением view с экрана. Используется для отмены операций, сохранения состояния, снятия подписок.
  • viewDidDisappear(_:) - вызывается после полного исчезновения view. Здесь можно освобождать ресурсы, останавливать анимации.

Управление памятью:

  • didReceiveMemoryWarning - вызывается при нехватке памяти. Нужно освобождать кэши, пересоздаваемые ресурсы.
  • deinit - вызывается при уничтожении контроллера. Освобождение всех ресурсов, отписка от NotificationCenter.

Важные нюансы:

  • Порядок вызовов при первом показе: loadViewviewDidLoadviewWillAppearviewDidAppear.
  • При повторном показе (например, после dismiss или pop): viewWillAppearviewDidAppear - без повторного viewDidLoad.
  • При переходе на другой контроллер (push/present): сначала вызываются viewWillDisappear и viewDidDisappear текущего, затем viewWillAppear и viewDidAppear нового.
  • viewDidLoad не гарантирует, что view уже на экране - только что загружена в память.
  • В iOS 13+ при свайпе назад с edge-swipe порядок может быть: viewWillDisappearviewWillAppear (если жест отменён) → viewDidAppear.

На практике

Для senior-позиции важно не просто перечислить методы, а показать понимание, когда что использовать и какие подводные камни бывают.

Типичные сценарии:

  • viewDidLoad - настройка один раз: создание элементов, начальные значения, подписки на Combine/NotificationCenter.
  • viewWillAppear - обновление данных при каждом показе: перезагрузка таблицы, обновление UI из модели, изменение title.
  • viewDidAppear - старт анимаций, отправка аналитики, показ onboarding.
  • viewWillDisappear - отмена сетевых запросов, сохранение черновиков, скрытие клавиатуры.
  • viewDidDisappear - остановка анимаций, освобождение тяжёлых ресурсов (например, видео).

Практические рекомендации:

  • Не выполняйте тяжёлые операции в viewDidLoad - это замедлит первый показ.
  • Используйте viewWillAppear для обновления данных, если они могли измениться на предыдущем экране.
  • При работе с NotificationCenter подписывайтесь в viewWillAppear и отписывайтесь в viewWillDisappear, чтобы избежать утечек при переходах.
  • Для кэшируемых данных используйте didReceiveMemoryWarning для очистки.
  • Внимательно с порядком при модальных презентациях: viewWillDisappear вызывается у presenting контроллера, но viewDidDisappear - только после завершения анимации.

Пример кода

SWIFT
final class ProfileViewController: UIViewController {
private let networkService = NetworkService()
private var data: [String] = []
override func loadView() {
super.loadView()
// Если нужно создать view вручную
// view = CustomView(frame: UIScreen.main.bounds)
}
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
configureNavigationBar()
// Начальная загрузка данных - но не тяжёлая
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Обновляем данные при каждом показе
refreshData()
// Подписка на уведомления
NotificationCenter.default.addObserver(
self,
selector: #selector(handleNotification),
name: .someNotification,
object: nil
)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Аналитика
Analytics.trackScreen("Profile")
// Старт анимации
startLoadingAnimation()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Отписка от уведомлений
NotificationCenter.default.removeObserver(self)
// Сохранение состояния
saveDraft()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// Остановка анимации
stopLoadingAnimation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Очистка кэша
imageCache.removeAll()
}
deinit {
// Полная очистка
networkService.cancelAllRequests()
}
}

Как отвечать на собеседовании

Начните с краткого перечисления методов в правильном порядке, затем переходите к деталям. Покажите понимание, что viewDidLoad - одноразовый, а viewWillAppear/viewDidAppear - повторяемые. Обязательно упомяните loadView и didReceiveMemoryWarning - это отличает senior от junior.

Хорошая структура ответа:

  1. Перечислите методы в порядке вызова.
  2. Объясните, что происходит на каждом этапе.
  3. Приведите пример, когда что использовать.
  4. Упомяните edge case: повторный показ, модальные переходы, обработка памяти.

Если спросят про конкретный сценарий (например, "что будет при push нового контроллера"), опишите порядок вызовов для обоих контроллеров.

Что проверяет интервьюер

  • Понимание разницы между одноразовыми и повторяемыми вызовами.
  • Знание loadView и когда его переопределяют.
  • Понимание управления памятью: didReceiveMemoryWarning, deinit.
  • Умение применять методы на практике: где подписываться, где отписываться.
  • Осознание порядка вызовов при переходах между контроллерами.
  • Понимание, что viewDidLoad не означает, что view на экране.

Типичные ошибки

  • Путаница между viewDidLoad и viewWillAppear - кандидат не понимает, что первый вызывается один раз.
  • Забывают про loadView или не могут объяснить, зачем он нужен.
  • Не упоминают didReceiveMemoryWarning - для senior это критично.
  • Подписываются на NotificationCenter в viewDidLoad и не отписываются - утечка памяти.
  • Выполняют тяжёлые операции в viewDidLoad, замедляя первый показ.
  • Не знают порядок вызовов при модальных переходах или edge-swipe.
  • Говорят, что viewDidLoad вызывается при каждом показе - грубая ошибка.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью