Как в UIViewController отследить поворот экрана или изменение размеров?

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

Ответ

Основной метод — viewWillTransition(to:with:). Он предпочтительнее уведомлений, так как работает универсально на всех устройствах (включая iPad с многозадачностью).

Использование viewWillTransition(to:with:):

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    // size — новые размеры view контроллера
    let isLandscape = size.width > size.height

    // coordinator позволяет встроить свою анимацию в системную
    coordinator.animate(alongsideTransition: { [weak self] _ in
        // Анимируем изменения layout при повороте
        self?.updateLayoutForOrientation(isLandscape: isLandscape)
    }) { [weak self] _ in
        // Действия после завершения анимации поворота
        self?.logOrientationChange()
    }
}

private func updateLayoutForOrientation(isLandscape: Bool) {
    // Обновляем constraints или frames
    someConstraint.constant = isLandscape ? 100 : 50
    view.layoutIfNeeded() // Применяем изменения с анимацией
}

Альтернатива — уведомление (менее предпочтительно):

// Подписка (например, в viewDidLoad)
NotificationCenter.default.addObserver(
    self,
    selector: #selector(orientationDidChange),
    name: UIDevice.orientationDidChangeNotification,
    object: nil
)

@objc private func orientationDidChange() {
    let orientation = UIDevice.current.orientation
    // Обработка...
}

Почему viewWillTransition лучше?

  1. Универсальность: Срабатывает при любом изменении размера view (поворот, split view на iPad, изменение window size).
  2. Координация анимаций: UIViewControllerTransitionCoordinator позволяет синхронизировать ваши анимации с системными.
  3. Контроль: Вы получаете точные новые размеры (CGSize), а не абстрактную "ориентацию устройства".

Дополнительно: Для реагирования на изменение размеров, вызванное Auto Layout, также можно переопределить viewWillLayoutSubviews() или traitCollectionDidChange(_:) (для изменений trait collections, таких как size class).