Можно ли отменить задачу в Grand Central Dispatch (GCD)?

«Можно ли отменить задачу в Grand Central Dispatch (GCD)?» — вопрос из категории Многопоточность, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Прямого аналога cancel() для DispatchQueue нет, но отмену можно реализовать с помощью DispatchWorkItem. У этого объекта есть методы cancel() и свойство isCancelled.

Пример отмены задачи:

// 1. Создаем workItem с проверкой отмены внутри
let workItem = DispatchWorkItem {
    // Периодически проверяем, не отменена ли задача
    for i in 1...10 {
        // Выходим из цикла, если задача отменена
        if Thread.isCancelled { break } // Или workItem.isCancelled, если доступно
        print("Шаг (i)")
        sleep(1)
    }
}

// 2. Ставим задачу в очередь на выполнение
let queue = DispatchQueue.global(qos: .utility)
queue.async(execute: workItem)

// 3. Отменяем задачу через 3 секунды (до или во время выполнения)
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
    workItem.cancel()
    print("Задача отменена")
}

Важные детали:

  • cancel() — кооперативный: Вызов workItem.cancel() только устанавливает флаг isCancelled. Он не прерывает уже выполняющийся блок кода. Код внутри DispatchWorkItem должен самостоятельно проверять этот флаг и корректно завершаться.
  • Отмена до выполнения: Если задача еще не начала выполняться, cancel() предотвратит её запуск.
  • Альтернатива: Для более сложных сценариев с зависимостями и приоритетами лучше подходит Operation и OperationQueue, где у Operation есть полноценный механизм отмены (cancel(), isCancelled).