> В чем разница между run loop и dispatch queue (iOS, Swift)

Уровень: senior · Роль: mobile · Категория: Технические вопросы

Компании: Doubletapp

Стек: iOS, Swift

> Пример ответа

Короткий ответ

Run loop - это механизм обработки событий в рамках одного потока: он крутится в цикле, принимает события из источников (таймеры, input sources) и диспетчеризует их в обработчики. Dispatch queue - это очередь задач, которая управляет выполнением блоков кода на одном или нескольких потоках, используя пул потоков. Главное различие: run loop - это цикл событий конкретного потока, а dispatch queue - абстракция над планированием задач, не привязанная к конкретному потоку.

Подробное объяснение

Run loop - это низкоуровневый механизм, который существует у каждого потока (по умолчанию у главного потока он запущен автоматически). Он работает по принципу: "спи, пока не появится событие, затем обработай его и снова спи". Источники событий: таймеры, порты, кастомные input sources, observer-уведомления. Run loop не выполняет произвольный код - он только обрабатывает события, которые ему явно переданы.

Dispatch queue - это часть Grand Central Dispatch (GCD). Очередь - это структура данных FIFO, в которую вы кладете блоки кода. GCD сам решает, на каком потоке и когда выполнить блок. DispatchQueue.main - это серийная очередь, привязанная к главному потоку, но это скорее исключение: остальные очереди не привязаны к конкретным потокам. GCD управляет пулом потоков, создает и уничтожает их по необходимости.

Ключевые различия:

  • Управление: run loop управляется вручную (вы сами решаете, когда запустить, остановить, какие источники добавить). Dispatch queue управляется системой - вы просто отправляете задачи.
  • Потоки: run loop привязан к конкретному потоку. Dispatch queue может выполняться на разных потоках (кроме main queue).
  • Назначение: run loop - для обработки событий (UI, networking, timers). Dispatch queue - для выполнения задач (в том числе длительных вычислений).
  • Взаимодействие: run loop может использовать dispatch queue как источник событий (через dispatch_source), но не наоборот.

На практике run loop редко используется напрямую в современном iOS-разработке - он скрыт внутри UIKit/Foundation (например, в RunLoop.main). Dispatch queue - основной инструмент для конкурентности.

На практике

В повседневной разработке вы почти никогда не создаете run loop вручную. Главный run loop управляет обработкой UI-событий, таймеров и блоков, отправленных на main queue. Если вы используете Timer, он добавляется в run loop текущего потока (по умолчанию - в default mode). Если вы используете DispatchQueue.main.async, GCD ставит блок в очередь и "будит" главный run loop через специальный механизм.

Dispatch queue используется для: фоновых вычислений, сетевых запросов, парсинга данных, работы с файлами. Выбор между serial и concurrent queue зависит от задачи: серийная очередь гарантирует порядок выполнения, конкурентная - параллелизм.

Важный нюанс: если вы работаете с URLSession, его completion handler по умолчанию выполняется на фоновой очереди, но вы можете указать delegate queue. Если вы используете RunLoop.main для планирования повторяющихся задач - это работает, но менее гибко, чем DispatchSourceTimer.

Пример кода

SWIFT
// Run loop - ручное управление
let runLoop = RunLoop.current
let timer = Timer(timeInterval: 1.0, repeats: true) { _ in
print("tick")
}
runLoop.add(timer, forMode: .common)
runLoop.run() // блокирует текущий поток
// Dispatch queue - отправка задач
let queue = DispatchQueue(label: "com.example.background", qos: .userInitiated)
queue.async {
// тяжелая работа
print("background task")
}
DispatchQueue.main.async {
// обновление UI
print("main thread")
}

Как отвечать на собеседовании

Начните с простого определения: run loop - это цикл обработки событий потока, dispatch queue - это очередь задач. Затем покажите разницу через примеры: run loop нужен для обработки событий (таймеры, UI), dispatch queue - для выполнения произвольных блоков. Подчеркните, что run loop привязан к потоку, а dispatch queue - нет. Упомяните, что GCD может использовать run loop для доставки задач на главный поток, но это внутренняя деталь. Если спросят про производительность: run loop - это механизм с низкой задержкой для событий, dispatch queue - более высокоуровневый и удобный для конкурентности.

Что проверяет интервьюер

Интервьюер хочет убедиться, что вы понимаете фундаментальные механизмы конкурентности в iOS, а не просто используете DispatchQueue.main.async по привычке. Проверяется: понимание модели потоков, знание того, как работает главный поток, умение объяснить, почему Timer на фоновом потоке не срабатывает без добавления в run loop, осознание разницы между синхронным и асинхронным выполнением. Также важно, что вы можете объяснить, когда какой инструмент использовать: run loop - для событий, dispatch queue - для задач.

Типичные ошибки

  • Утверждение, что run loop и dispatch queue - это одно и то же.
  • Утверждение, что dispatch queue создает поток - это не так, GCD управляет пулом потоков.
  • Игнорирование того, что Timer требует run loop: если вы создаете Timer на фоновом потоке без добавления в run loop, он не сработает.
  • Смешение понятий: main queue и main run loop - это разные вещи, хотя и связанные.
  • Непонимание, что run loop может быть остановлен или не запущен вовсе, а dispatch queue работает всегда, пока есть задачи.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью