Какие вьюшки присутствуют в иерархии UINavigationController с пятью запушенными UIViewController: всех пяти или только видимого
Что проверяют
Различаете ли вы стек контроллеров и иерархию вью: это разные вещи, и ответ зависит от того, про что именно спросили. Следом обычно спрашивают, живы ли в памяти нижние контроллеры и что происходит с их вью.
Как отвечать
Разведите два уровня:
- стек контроллеров: массив
viewControllersдержит сильные ссылки на все пять, объекты живы,topViewControllerэто последний запушенный; - иерархия вью в окне: после завершения перехода в ней остаётся только вью верхнего контроллера. Навигационный контроллер убирает вью предыдущего экрана из иерархии, и у нижних контроллеров
view.windowравенnil.
Проверить легко в Debug View Hierarchy в Xcode: под UINavigationBar и контейнером переходов лежит одна вью контента, хотя в стеке пять контроллеров.
Уточнения, которые делают ответ сильным:
- во время перехода: при анимированном push или pop и при интерактивном свайпе назад в контейнере одновременно находятся две вью, уходящая и приходящая;
- вью нижних экранов не выгружаются: если экран уже показывался, его вью остаётся в памяти (
isViewLoadedвернётtrue), просто не висит в окне. Автоматической выгрузки вью при нехватке памяти, как во временаviewDidUnload, давно нет; - ленивая загрузка: если стек собран сразу через
setViewControllers(_:animated:), вью промежуточных контроллеров не загружаются, пока вы к ним не вернётесь; - события: при push нижний контроллер получает
viewWillDisappearиviewDidDisappear, при возврате сноваviewWillAppear, но неviewDidLoad.
Где спотыкаются
Отвечают «все пять», смешивая массив viewControllers с деревом вью. В памяти действительно пять контроллеров, но в иерархии окна одна вью контента.
Считают, что вью нижних экранов уничтожаются и создаются заново при возврате, и кладут обновление данных в viewDidLoad. Вернувшийся экран получит только viewWillAppear, и данные останутся старыми.
Не освобождают тяжёлое, когда экран уходит вглубь стека: видео, таймеры и подписки продолжают работать, хотя экран никто не видит. Останавливать их стоит в viewWillDisappear или viewDidDisappear.