Как определить в UIView, что она добавлена или удалена с экрана для управления анимациями и подписками
Что проверяют
Различаете ли вы «добавлена в иерархию» и «видна на экране». Интервьюер ждёт, что вы выберете правильный хук и не запустите анимацию во вью, которая лежит в неотображённом контейнере. Следом обычно спрашивают про ячейки коллекций и уход приложения в фон.
Как отвечать
У UIView две пары методов:
willMove(toSuperview:)иdidMoveToSuperview(): вызываются при смене родителя, в том числе приremoveFromSuperview()сnil. Но родитель сам может быть вне окна, так что это ещё не экран;willMove(toWindow:)иdidMoveToWindow(): вызываются, когда вью попадает в окно или покидает его. Для этой задачи это лучший сигнал:window != nilзначит, что вью в живой иерархии.
Типичная реализация: в didMoveToWindow() при window != nil запускаете анимацию и подписываетесь, например сохраняете AnyCancellable из Combine или токен NotificationCenter. При window == nil отменяете подписки и снимаете анимации. Метод может вызваться несколько раз, поэтому подписку делайте идемпотентной: сначала отменить старую, потом создать новую.
Назовите случаи, где сигнал окна не помогает:
- ячейки
UICollectionViewиUITableView: переиспользуются и не обязательно уходят из окна. Видимость ловят вwillDisplayиdidEndDisplayingделегата, сброс состояния делают вprepareForReuse(); - навигация: после push или полноэкранного показа предыдущий экран снимается с окна, а под
.pageSheetостаётся. На уровне контроллера надёжнееviewWillAppearиviewDidDisappear; - фон: при сворачивании окно остаётся, нужны
UIApplication.didEnterBackgroundNotificationили аналог уUIScene; - перекрытие: вью в окне, но скрыта
isHidden, нулевойalphaили прокручена за край.
Где спотыкаются
Опираются только на didMoveToSuperview(). Вью добавили в контейнер, который ещё не показан, а анимация и сетевые подписки уже работают.
Подписываются при каждом didMoveToWindow() без отмены прежней подписки. После пары переходов обработчик срабатывает дважды и трижды.
Держат self сильно в замыкании подписки и ждут отписки в deinit. Вью не освобождается как раз из-за этой подписки, и deinit не наступает.