Ответ
Нет. Методы жизненного цикла, связанные с view (viewDidLoad, viewWillAppear и т.д.), не вызываются во время инициализации контроллера через init(nibName:bundle:) или init(coder:).
Последовательность событий
- Инициализация (
init): Создается сам объектUIViewController. Его view (self.view) еще не загружена и равнаnil. - Загрузка View (ленивая): При первом обращении к свойству
view(например, из кода или при добавлении контроллера в иерархию) система запускает процесс загрузки. - Вызов методов жизненного цикла: Только после успешной загрузки view вызываются соответствующие методы.
Практический пример
class DemoViewController: UIViewController {
// 1. Инициализация
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
print("1. init called. View is nil? (self.view == nil)") // true
}
// 2. Загрузка View (системный вызов)
override func loadView() {
print("2. loadView called")
view = UIView() // Создаем view вручную
}
// 3. View загружена и готова
override func viewDidLoad() {
super.viewDidLoad()
print("3. viewDidLoad called. View is nil? (self.view == nil)") // false
// Здесь безопасно настраивать элементы интерфейса.
}
// 4. View появится на экране
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("4. viewWillAppear called")
}
}
// Использование:
let vc = DemoViewController(nibName: nil, bundle: nil) // Выведет только "1. init..."
// vc.view // Раскомментировать для принудительной загрузки view и вызова 2, 3.
Важное следствие: Не пытайтесь обращаться к self.view или outlet-ам внутри init. Они будут nil. Вся настройка, зависящая от view, должна выполняться в viewDidLoad() или позже.
Ответ 18+ 🔞
Да ты посмотри, какая история-то интересная вырисовывается, блядь! Вот сидишь ты, такой весь из себя умный, думаешь: «Создам я контроллер, и сразу в init начну view настраивать, хуле». А нихуя!
Смотри сюда, распиздяйство полное. Эти все твои любимые методы — viewDidLoad, viewWillAppear и прочая хуйня — вообще не зовутся, пока ты контроллер через init создаёшь. Вообще. Тишина, блядь.
Как это работает, на самом деле? А вот как, слушай, не гони:
-
init— это просто рождение голого тела. Ты вызвалinit(nibName:bundle:). Система тебе выдала объектUIViewController. А его view, эта самаяself.view— она в этот момент вообщеnil, пустота, пиздец. Её нет. Ты к ней обратишься — тебеnilи выедет, и волнение ебать. -
View загружается, когда её тронули. Она, сука, ленивая, как мартышлюшка после обеда. Загрузится только тогда, когда кто-то впервые попробует к ней доступ получить. Либо ты в коде напишешь
vc.view, либо система её сама запросит, когда контроллер на экран выводить будет. -
А вот тут уже начинается магия. Только после того, как view загрузили (в
loadView), система такая: «Ага, ну теперь-то можно!». И начинает орать на все методы жизненного цикла.viewDidLoad— первый в этой очереди.
Пример, чтобы совсем пиздец понятно стало
class DemoViewController: UIViewController {
// 1. Родили голое тело
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
print("1. init вызван. View есть? (self.view == nil)") // true, блядь, её нет!
// Сюда пихать настройку интерфейса — это всё равно что хуй с горы кидать. Не попадёшь.
}
// 2. Система пошла view грузить
override func loadView() {
print("2. loadView вызван")
view = UIView() // Вот тут мы её, родимую, создаём
}
// 3. О, ёпта! View загрузилась!
override func viewDidLoad() {
super.viewDidLoad()
print("3. viewDidLoad вызван. View есть? (self.view == nil)") // false, ура!
// Вот тут уже можно безопасно ковыряться в интерфейсе. Всё на месте.
}
// 4. А вот это уже когда на экран полезем
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("4. viewWillAppear вызван")
}
}
// Используем:
let vc = DemoViewController(nibName: nil, bundle: nil)
// В консоли будет ТОЛЬКО: "1. init вызван. View есть? true"
// И ВСЁ. Тишина. viewDidLoad молчит, как Герасим немой.
// А вот если раскомментировать строчку ниже, тогда начнётся движ:
// let _ = vc.view // Система полезет view грузить, и в консоли появится 2, 3, 4.
И главный вывод, который бьёт, как кирпичом по ебалу: Не лезь ты в init с настройкой self.view или аутлетов. Они там — nil, пизда. Вся работа с интерфейсом должна быть в viewDidLoad() или позже, когда view уже точно есть. Иначе будешь потом охуевать, почему у тебя кнопки не отображаются, а в консоли краши летят.