В каком методе UIViewController можно программно создать его корневое view?

Ответ

Корневое 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'ов. Всё, вопрос закрыт, иди работай.