Ответ
Корневое view контроллера можно создать, переопределив метод loadView().
Назначение: Система вызывает этот метод, когда требуется создать view-иерархию контроллера. Если метод не переопределен, iOS загружает view из storyboard или nib-файла.
Пример создания view вручную:
class CustomViewController: UIViewController {
override func loadView() {
// 1. Создаем кастомное view
let customView = UIView()
customView.backgroundColor = .systemBackground
// 2. Добавляем subviews
let label = UILabel()
label.text = "Hello, World!"
customView.addSubview(label)
// ... настройка constraints
// 3. КРИТИЧЕСКИ ВАЖНО: присвоить self.view
self.view = customView
}
// viewDidLoad() будет вызван после loadView()
override func viewDidLoad() {
super.viewDidLoad()
// Дополнительная настройка уже созданного view
}
}
Ключевые правила:
- Не вызывайте
super.loadView(), если создаете view полностью самостоятельно. - Обязательно присвойте свойство
self.view, иначе произойдет crash. - Метод
loadView()вызывается один раз за жизненный цикл контроллера, доviewDidLoad(). - Используйте этот метод, когда view создается исключительно кодом, без Interface Builder.
Ответ 18+ 🔞
Ну слушай, смотри, вот есть у тебя контроллер, да? И view у него, блядь, откуда-то же должно взяться. Обычно-то оно из сториборда приплывает, как по маслу. Но иногда, сука, надо всё руками, по-старинке, внатуре, без этих твоих Interface Builder'ов, которые только мозги ебут.
Так вот, есть у тебя такой метод, loadView(), ёпта. Система его дергает, когда ей уже пиздец как нужно, чтобы у контроллера view появилось. Если ты его не трогаешь — ну, молодец, система сама всё сделает, как умеет. А если хочешь быть крутым перцем и собрать вьюху сам, как бог на душу положит — вот тут ты его и переопределяешь.
Смотри, как это выглядит, на примере, чтобы не быть мудаком, который потом ищет, почему крашится:
class CustomViewController: UIViewController {
override func loadView() {
// 1. Создаем кастомное view
let customView = UIView()
customView.backgroundColor = .systemBackground
// 2. Добавляем subviews
let label = UILabel()
label.text = "Hello, World!"
customView.addSubview(label)
// ... настройка constraints
// 3. КРИТИЧЕСКИ ВАЖНО: присвоить self.view
self.view = customView
}
// viewDidLoad() будет вызван после loadView()
override func viewDidLoad() {
super.viewDidLoad()
// Дополнительная настройка уже созданного view
}
}
Видишь? Всё просто, как три копейки. Создал вьюху, навертел на неё чего хотел, и — внимание, ебаный в рот! — присвоил self.view. Это, блядь, святое. Не сделаешь — получишь краш и будешь потом как Герасим, «му-му» говорить, а нихуя не поймёшь, в чём дело.
И ещё запомни, чувак, раз и навсегда: не вызывай super.loadView(), если делаешь всё с нуля. Ты ж не хочешь, чтобы система рядом со твоим кастомным вью ещё и своё какое-нибудь левое говно притащила? Вот и не вызывай.
Вызывается этот метод один раз, в самом начале, ещё до того, как viewDidLoad() зашевелится. Используй его, когда тебе нужно собрать вьюху голыми руками, без всяких там сторибордов и xib'ов. Всё, вопрос закрыт, иди работай.