Когда использовать OperationQueue, а когда DispatchQueue в iOS?

«Когда использовать OperationQueue, а когда DispatchQueue в iOS?» — вопрос из категории Многопоточность, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

DispatchQueue (GCD) и OperationQueue — инструменты для многопоточности, но разного уровня абстракции и возможностей.

DispatchQueue (Grand Central Dispatch)

  • Уровень: Низкоуровневый C API.
  • Модель: Очереди (serial/concurrent) + блоки кода (closures).
  • Ключевые особенности:
    • Простота и эффективность для разовых задач.
    • Управление через Quality of Service (QoS): .userInteractive, .background и т.д.
    • Нет встроенной поддержки зависимостей между задачами.
    • Сложность отмены запущенной задачи.

Пример: Простая фоновая задача.

let backgroundQueue = DispatchQueue(label: "com.app.background", qos: .background)
backgroundQueue.async {
    let processedData = heavyCalculation()
    DispatchQueue.main.async {
        updateUI(with: processedData)
    }
}

OperationQueue

  • Уровень: Высокоуровневая абстракция на основе Operation (объектно-ориентированная).
  • Модель: Очередь операций (Operation подклассы или BlockOperation).
  • Ключевые особенности:
    • Зависимости: Операции могут ждать завершения других (addDependency).
    • Отмена: Легко отменить всю очередь или конкретную операцию (cancel()).
    • Контроль параллелизма: maxConcurrentOperationCount.
    • Наблюдение: KVO для свойств isFinished, isCancelled.
    • Переиспользование: Можно создавать библиотеки операций.

Пример: Задачи с зависимостями.

let downloadQueue = OperationQueue()
downloadQueue.maxConcurrentOperationCount = 2

let downloadOp = BlockOperation { downloadFile() }
let parseOp = BlockOperation { parseFile() }
let updateUIOp = BlockOperation { DispatchQueue.main.async { updateUI() } }

// Установка зависимостей: парсинг ждет загрузки, UI ждет парсинга.
parseOp.addDependency(downloadOp)
updateUIOp.addDependency(parseOp)

// Добавление на очередь
downloadQueue.addOperations([downloadOp, parseOp], waitUntilFinished: false)
OperationQueue.main.addOperation(updateUIOp)

Сводная таблица выбора

Критерий Выберите DispatchQueue Выберите OperationQueue
Зависимости задач Нет Да (ключевое преимущество)
Приоритет отмены Низкий Высокий (легко отменить)
Тип задачи Простая, разовая Сложная, составная, переиспользуемая
Контроль параллелизма Только через типы очередей Точный контроль (maxConcurrentOperationCount)
Состояние задачи Не отслеживается Отслеживается (KVO)

Практическое правило: Начинайте с DispatchQueue для простых асинхронных задач. Переходите на OperationQueue, когда появляются зависимости между задачами, требование их отмены или необходимость сложного управления очередью.