В каком методе жизненного цикла UIViewController следует запускать анимации интерфейса?

Ответ

Оптимальный метод для запуска большинства анимаций – viewDidAppear(_:).

Почему не viewDidLoad или viewWillAppear? На этих этапах view может быть добавлена в иерархию, но ее layout (размеры и положение) еще не окончательный. Анимация, зависящая от frame или bounds, может работать некорректно.

Пример правильного запуска:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // Простая анимация появления
    UIView.animate(withDuration: 0.5, delay: 0.1, options: .curveEaseOut) {
        self.welcomeLabel.alpha = 1.0
        self.welcomeLabel.transform = .identity
    }

    // Запуск циклической анимации (например, индикатор загрузки)
    startLoadingAnimation()
}

Дополнительные рекомендации:

  1. Для гарантии можно обернуть вызов в DispatchQueue.main.async:

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        DispatchQueue.main.async {
            // Анимация гарантированно запустится после полного отображения
            self.animateIntroSequence()
        }
    }
  2. Анимации, не зависящие от layout, можно запускать в viewWillAppear (например, изменение alpha с 0 на 1).

  3. Используйте viewWillLayoutSubviews или viewDidLayoutSubviews для анимаций, которые должны реагировать на изменение размеров (например, при повороте устройства).

  4. Останавливайте анимации в viewWillDisappear или viewDidDisappear, чтобы избежать утечек ресурсов и работы в фоне.

Итог: viewDidAppear обеспечивает корректные размеры view и плавный пользовательский опыт.

Ответ 18+ 🔞

Да ты посмотри, какая история! Весь этот цирк с анимациями, а запустить их вовремя — целое искусство, ёпта.

Вот смотри, народ часто, как дурак, тычет это всё в viewDidLoad или viewWillAppear. А потом сидит, чешет репу: "Чё за хуйня? Анимация не работает, или прыгает как угорелая!". А потому что, блядь, вьюха вроде и есть, а её настоящие размеры и положение — ещё не готовы! Она как будто в подвешенном состоянии, этот layout ещё не проставился. Представь, ты начинаешь бежать, а дистанцию тебе объявят через пять секунд. Пиздец, да?

Поэтому, чтоб не было мудацких сюрпризов, юзай viewDidAppear(_:). Тут уже всё расставлено по полочкам, вьюха отрисована, и можно её двигать без опаски.

Вот, смотри, как по-человечески:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // Простая анимация появления
    UIView.animate(withDuration: 0.5, delay: 0.1, options: .curveEaseOut) {
        self.welcomeLabel.alpha = 1.0
        self.welcomeLabel.transform = .identity
    }

    // Запуск циклической анимации (например, индикатор загрузки)
    startLoadingAnimation()
}

А если ты параноик, как я (а в разработке это полезно), то можешь на всякий пожарный завернуть это в DispatchQueue.main.async. Типа, дадим системе окончательно всё выплюнуть и успокоиться, а потом уже начнём наш цирк:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    DispatchQueue.main.async {
        // Анимация гарантированно запустится после полного отображения
        self.animateIntroSequence()
    }
}

Ну и, блядь, не забудь про уборку за собой! Если у тебя там какая-нибудь бесконечная анимация крутится, как сумасшедшая мартышлюшка, её надо прибить в viewWillDisappear. А то она будет в фоне ресурсы жрать, а пользователь уже на другом экране чай пьёт. Экономия батареи, мать её!

Короче, запомни: для большинства показух — viewDidAppear. И будет тебе счастье, а не волнение ебать.