Сколько стеков может быть в приложении и почему
Что проверяют
Понимаете ли вы, что стек вызовов принадлежит потоку, и слышите ли двусмысленность вопроса: в iOS стеком называют и стек вызовов, и стек экранов навигации. Хороший ответ начинается с уточнения, а не с числа.
Как отвечать
Если речь про стек вызовов, их столько, сколько потоков: свой у главного, свой у каждого фонового. Что стоит добавить:
- главный поток в iOS получает стек в один мегабайт, вторичные по умолчанию 512 килобайт. Размер вторичного задаётся через
stackSizeуThreadдо запуска и выравнивается по размеру страницы; - очередь в GCD это не поток. Задачи разных очередей могут выполняться на одном потоке пула, а блокирующие вызовы внутри задач разгоняют пул и порождают лишние стеки;
- в Swift Concurrency кооперативный пул держит примерно по потоку на ядро, а приостановленная асинхронная функция поток не занимает: её кадры живут вне стека потока.
Если вопрос всё-таки про навигацию, ответ другой: свой стек экранов у каждого UINavigationController, то есть в приложении с таб-баром их обычно столько, сколько вкладок, плюс модально представленные контроллеры со своими.
Где спотыкаются
Отвечают «один, главный». Дальше сразу спрашивают, где же выполняется код фоновой загрузки, и объяснить это одним стеком не получается.
Приравнивают очереди к потокам. Тысяча задач на глобальной очереди не означает тысячу стеков, но и не означает один: именно блокирующая работа внутри задач приводит к разрастанию пула, и про это спрашивают следом.
Пытаются лечить падение от глубокой рекурсии увеличением stackSize. Стек главного потока так не увеличить вовсе, а упор в стек почти всегда означает, что рекурсию надо переписать циклом или сделать хвостовой обход явным.