Сколько run loop в приложении и какие правила или зависимости существуют
Что проверяют
Знаете ли вы, что цикл привязан к потоку и что наличие цикла не значит, что его кто-то крутит. Спрашивают про правила и зависимости, поэтому ждут не определение, а условия, при которых таймеры и источники событий действительно срабатывают.
Как отвечать
Правило первое: у потока может быть не больше одного цикла, и объект создаётся лениво, при первом обращении через RunLoop.current. Передать чужой цикл в другой поток нельзя, он принадлежит своему потоку.
Правило второе: главный поток особый. Его цикл заводит и запускает точка входа приложения, он крутится всё время жизни процесса и доставляет касания, перерисовку и таймеры интерфейса.
Правило третье: у побочного потока цикл есть, но не работает. Пока поток не запустит его сам, ничего не произойдёт, и запущенный цикл завершится сразу, если в нём нет ни одного источника, таймера или порта.
Правило четвёртое: режимы. Таймер, добавленный в режим по умолчанию, замолкает во время прокрутки, потому что цикл переключается в режим отслеживания. Поэтому таймеры добавляют в общий режим.
let timer = Timer(timeInterval: 1, repeats: true) { _ in }
RunLoop.current.add(timer, forMode: .common)Про зависимости добавьте, что очереди GCD собственных циклов не имеют, кроме главной очереди, которую обслуживает главный цикл. Для повторяющихся задач в фоне берут DispatchSourceTimer.
Где спотыкаются
Считают, что цикл запущен у каждого потока сразу. Отсюда классический баг: таймер, заведённый на своём потоке, молча не срабатывает, а логи чистые, потому что ошибки нет, просто некому доставлять событие.
Второе: не знают про режимы и приходят с жалобой, что во время прокрутки список перестаёт обновляться. Виноват не таймер и не главный поток, а режим, в который цикл переключился на время жеста.
Третье: путают цикл с очередью. Ожидание, что Timer заработает на глобальной очереди, ошибочно: там нет цикла, который его обслужит, и задача просто не запустится.