Что является более низкоуровневым в iOS: GCD или OperationQueue?

Ответ

Grand Central Dispatch (GCD) является более низкоуровневым API. OperationQueue построен поверх GCD и предоставляет объектно-ориентированную, высокоуровневую абстракцию.

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

  • GCD работает напрямую с системными потоками через очереди (DispatchQueue). Он легковесный и эффективный для простых задач.
  • OperationQueue использует GCD внутри, но добавляет возможности, отсутствующие в чистом GCD:
    • Зависимости между операциями (addDependency(_:)).
    • Отмена операций (cancel()).
    • Приоритеты операций (queuePriority).
    • Наблюдение за состоянием через KVO-совместимые свойства (isReady, isExecuting, isFinished).
    • Ограничение параллелизма (maxConcurrentOperationCount).

Примеры:

GCD (низкоуровневый):

DispatchQueue.global(qos: .userInitiated).async {
    // Выполняем работу
    let result = performHeavyCalculation()
    DispatchQueue.main.async {
        // Обновляем UI
        updateUI(with: result)
    }
}

OperationQueue (высокоуровневый):

let downloadQueue = OperationQueue()
let processQueue = OperationQueue()
processQueue.maxConcurrentOperationCount = 1

let downloadOp = BlockOperation {
    let data = downloadData()
}
let processOp = BlockOperation {
    processData()
}

// Устанавливаем зависимость: обработка начнется только после загрузки
processOp.addDependency(downloadOp)

downloadQueue.addOperation(downloadOp)
processQueue.addOperation(processOp)

Выбор: Используйте GCD для простых, атомарных задач. OperationQueue предпочтительнее для сложных операций с зависимостями, требующих отмены или тонкого управления выполнением.

Ответ 18+ 🔞

Давай разберёмся, что за хуйня тут происходит с этими очередями в iOS. Сидишь, читаешь документацию, а там — GCD, OperationQueue... Глаза разбегаются, как у пиздюка на ёлке. Но на самом деле всё просто, если не забивать себе голову академическим бредом.

Вот смотри, есть Grand Central Dispatch (GCD) — это типа такой фундамент, основа основ. Низкоуровневое API, которое работает напрямую с системными потоками через свои очереди (DispatchQueue). Штука лёгкая, быстрая, для простых задач — просто огонь. Но как только начинаешь делать что-то сложное, понимаешь, что тебе не хватает инструментов. И тут на сцену выходит OperationQueue.

А OperationQueue — это уже надстройка, объектно-ориентированная абстракция, которая внутри себя использует тот же самый GCD. Но, блядь, добавляет кучу плюшек, которых в чистом GCD нет от слова совсем. Это как сравнивать голый двигатель и целый автомобиль с кондиционером и подогревом сидений.

В чём же разница, ёпта?

  • GCD — это прямые команды системе: «эй, система, выполни этот блок кода в фоне». Быстро, эффективно, но примитивно.
  • OperationQueue — это уже управляемый оркестр. Ты можешь:
    • Ставить зависимости между операциями — чтобы одна начиналась только после завершения другой. addDependency(_:) — и всё, магия!
    • Отменять операции на лету. cancel() — и операция понимает, что её больше не ждут.
    • Выставлять приоритеты — какая задача важнее.
    • Следить за состоянием операции (выполняется, готова, завершена) через KVO-совместимые свойства.
    • Ограничивать параллелизм — чтобы не перегрузить систему. maxConcurrentOperationCount = 1 — и у тебя последовательная очередь готова.

Примеры, чтобы совсем всё стало ясно, как божий день:

Вот как это делается на голом GCD (низкоуровнево):

DispatchQueue.global(qos: .userInitiated).async {
    // Делаем какую-то тяжёлую хуйню
    let result = performHeavyCalculation()
    DispatchQueue.main.async {
        // Возвращаемся в главный поток, чтобы обновить интерфейс
        updateUI(with: result)
    }
}

Всё просто: бросили в фоновую очередь, получили результат, вернулись в главную. Но попробуй тут что-то отменить или поставить в зависимость от другой задачи — придётся городить свой велосипед.

А вот как это выглядит на OperationQueue (высокоуровнево):

let downloadQueue = OperationQueue()
let processQueue = OperationQueue()
processQueue.maxConcurrentOperationCount = 1 // Обработка будет идти строго по одной операции

let downloadOp = BlockOperation {
    let data = downloadData() // Качаем данные
}
let processOp = BlockOperation {
    processData() // Обрабатываем их
}

// Вот она, магия! Обработка начнётся ТОЛЬКО после того, как загрузка завершится.
processOp.addDependency(downloadOp)

downloadQueue.addOperation(downloadOp)
processQueue.addOperation(processOp)

Видишь? Мы явно сказали системе: «Не трогай обработку, пока качалка не закончит свою работу». И всё это — парой строчек кода. Красота, ёпта!

Так что же выбрать, спросишь ты?

Да всё просто, как три копейки:

  • GCD — для простых, атомарных задач. Скинул в очередь — забыл.
  • OperationQueue — для сложных операций, где нужны зависимости, отмена, приоритеты и тонкое управление. Когда твоя логика начинает напоминать паутину, а не линейный сценарий.

Вот и вся наука. Не усложняй там, где не надо, но и не городи костыли из GCD, когда тебе нужен полноценный инструмент.