← Назад к вопросам
Вызывается ли жизненный цикл ViewController при его инициализации?
1.0 Junior🔥 261 комментариев
#UIKit и верстка
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Жизненный цикл ViewController при инициализации
Ответ: НЕТ, lifecycle методы не вызываются при инициализации
Это частая ошибка в понимании архитектуры iOS. При создании экземпляра ViewController вызывается только инициализатор (init), но lifecycle методы НЕ вызываются.
Фазы загрузки ViewController
1. Инициализация (Initialization)
// Фаза 1: init вызывается сразу
class MyViewController: UIViewController {
init() {
super.init(nibName: nil, bundle: nil)
// Инициализация свойств
print("1. init() — объект создан в памяти")
// Но lifecycle методы ещё НЕ вызваны!
}
required init?(coder: NSCoder) {
super.init(coder: coder)
print("1. init(coder:) — из Storyboard")
}
}
// ViewController создан, но не загружен
let controller = MyViewController()
// Вывод: "1. init() — объект создан в памяти"
// Больше ничего не вызывается!
2. Загрузка View (View Loading)
Lifecycle методы начинают вызываться только когда view физически загружается:
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("3. viewDidLoad() — view загружена, иерархия создана")
// Сейчас можно работать с UI элементами
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("4. viewWillAppear() — view вот-вот появится")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("5. viewDidAppear() — view видна пользователю")
}
}
// Создание controller НЕ вызывает эти методы!
let controller = MyViewController()
print("init завершен, но viewDidLoad ещё не вызван")
Полный порядок событий
let controller = MyViewController()
// Вывод:
// "1. init() — объект создан в памяти"
// Контроллер добавляется в view hierarchy
window.rootViewController = controller
// Вывод:
// "2. loadView() или view из XIB/Storyboard"
// "3. viewDidLoad() — view загружена"
// "4. viewWillAppear() — view вот-вот появится"
// "5. viewDidAppear() — view видна пользователю"
// Пользователь ушел с экрана
// Вывод:
// "6. viewWillDisappear() — view вот-вот исчезнет"
// "7. viewDidDisappear() — view больше не видна"
// При полной выгрузке
// Вывод:
// "8. deinit() — память освобождена"
Диаграмма события
┌─────────────────────────────────────┐
│ let controller = MyViewController() │
│ ✅ init() вызывается │
│ ❌ viewDidLoad() НЕ вызывается │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ window.rootViewController = ctl │
│ ✅ loadView() вызывается │
│ ✅ viewDidLoad() вызывается │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Переход на экран │
│ ✅ viewWillAppear() вызывается │
│ ✅ viewDidAppear() вызывается │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Переход со экрана │
│ ✅ viewWillDisappear() вызывается │
│ ✅ viewDidDisappear() вызывается │
└─────────────────────────────────────┘
Практический пример — частая ошибка
class ProfileViewController: UIViewController {
var user: User?
init(userID: String) {
super.init(nibName: nil, bundle: nil)
// ❌ ОШИБКА: Пытаемся обновить UI в init
// self.navigationItem.title = "Profile"
// Fatal error: view property of ProfileViewController is accessed
// before it is fully initialized
// ✅ Правильно: просто сохраняем данные
self.user = User(id: userID)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
// ✅ Теперь можно работать с view
self.navigationItem.title = user?.name ?? "Profile"
setupUI()
}
private func setupUI() {
// Конфигурация UI
}
}
Что вызывается в init
class MyViewController: UIViewController {
init() {
super.init(nibName: nil, bundle: nil)
// ✅ Допустимо: инициализация переменных
let config = AppConfig()
let viewModel = ViewModel()
// ✅ Допустимо: сохранение параметров
self.viewModel = viewModel
// ✅ Допустимо: конфигурация сервисов
self.analytics.setScreen("ProfileVC")
// ❌ Недопустимо: обращение к view
// self.label.text = "Hello"
// ❌ Недопустимо: обращение к подвьюхам
// self.view.addSubview(myView)
}
}
Когда вызывать loadView
class CustomViewController: UIViewController {
override func loadView() {
// ✅ loadView() вызывается ДО viewDidLoad()
// Здесь можно программно создать view
let rootView = UIView()
rootView.backgroundColor = .white
let label = UILabel()
label.text = "Hello"
rootView.addSubview(label)
self.view = rootView
}
override func viewDidLoad() {
super.viewDidLoad()
// Сейчас self.view определён и готов к использованию
}
}
Summary: Порядок вызовов
| Событие | init | loadView | viewDidLoad | viewWillAppear | viewDidAppear |
|---|---|---|---|---|---|
| Controller создан | ✅ | ❌ | ❌ | ❌ | ❌ |
| View добавлена в иерархию | ✅ | ✅ | ✅ | ❌ | ❌ |
| Переход на экран | ✅ | ✅ | ✅ | ✅ | ✅ |
Важные выводы
- init НЕ гарантирует жизненный цикл — используй инициализатор только для инициализации data
- viewDidLoad — точка старта — здесь можно безопасно работать с UI
- loadView — программное создание view — переопредели только если нужна кастомная иерархия
- viewWillAppear/viewDidAppear — видимость — используй для обновления данных и отписки от событий
- Тестируй с print() — добавь логирование во все методы жизненного цикла для понимания