Как iOS приложение обрабатывает поворот устройства (смену ориентации экрана)?

«Как iOS приложение обрабатывает поворот устройства (смену ориентации экрана)?» — вопрос из категории UIKit, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

При повороте устройства система iOS управляет переходом между портретной и ландшафтной ориентацией, запуская четкую последовательность событий в приложении.

Основной поток событий:

  1. Системное уведомление: Генерируется UIDevice.orientationDidChangeNotification.
  2. Запрос к контроллеру: Система запрашивает у UIViewController поддерживаемые ориентации через supportedInterfaceOrientations.
  3. Уведомление контроллера: Вызывается метод viewWillTransition(to:with:)ключевое место для ручной адаптации UI.
  4. Обновление трейтов: Может измениться traitCollection (например, horizontalSizeClass). После этого вызывается traitCollectionDidChange(_:).
  5. Пересчет layout: Система автоматически запускает процесс Auto Layout, вызывая view.layoutSubviews() и updateViewConstraints().

Практическая реализация:

class MyViewController: UIViewController {
    override func viewWillTransition(to size: CGSize,
                                   with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        // size — новые размеры view controller's view.
        // coordinator позволяет анимировать изменения вместе с поворотом.
        coordinator.animate(alongsideTransition: { context in
            // Анимируйте изменения, зависящие от ориентации (например, констрейнты).
            self.updateLayout(for: size)
        }, completion: { context in
            // Действия после завершения анимации поворота.
        })
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        // Ограничение списка допустимых ориентаций для этого контроллера.
        return [.portrait, .landscapeLeft]
    }

    override var shouldAutorotate: Bool {
        return true // Разрешить автоматический поворот.
    }
}

Best practices для адаптивного UI:

  • Полагайтесь на Auto Layout и Size Classes: Создавайте адаптивные констрейнты, используя widthAnchor, heightAnchor, и Stack Views. Размечайте интерфейс для разных horizontalSizeClass (Compact/Regular) в Interface Builder.
  • Определяйте ориентацию правильно: Не используйте UIDevice.current.orientation для логики layout. Вместо этого:
    let isLandscape = view.bounds.width > view.bounds.height
    // Или используйте размеры из viewWillTransition(to:with:).
  • Для отключения поворота: Верните .portrait в supportedInterfaceOrientations или false в shouldAutorotate.

Итог: Современный подход — создание адаптивных интерфейсов, которые работают при любом размере и ориентации, используя Auto Layout и Trait Collections, с тонкой настройкой в viewWillTransition(to:with:).