Ответ
NSOperation (и его подкласс NSBlockOperation) — это абстракция над задачей, которая должна быть выполнена. NSOperationQueue — это очередь для управления выполнением этих операций. Этот API построен поверх GCD (Grand Central Dispatch) и предоставляет более высокоуровневый контроль над асинхронными задачами.
Ключевые преимущества перед чистым GCD:
- Зависимости (
addDependency(_:)): Позволяют четко задавать порядок выполнения операций ("B не начнется, пока не завершится A"). - Отмена операций (
cancel()): Возможность отменить как еще не начатую, так и выполняющуюся операцию (с проверкой флагаisCancelledвнутри). - Наблюдение за состоянием: KVO-совместимые свойства (
isReady,isExecuting,isFinished,isCancelled). - Управление приоритетом:
queuePriority(в рамках одной очереди) иqualityOfService(аналогично QoS в GCD). - Ограничение параллелизма:
maxConcurrentOperationCountу очереди.
Пример создания кастомной операции:
class DataProcessingOperation: Operation {
let inputData: Data
var outputResult: Result?
init(data: Data) {
self.inputData = data
}
override func main() {
// 1. Всегда проверяем отмену в начале и во время долгой работы
guard !isCancelled else { return }
// 2. Выполняем основную работу
outputResult = processData(inputData)
// 3. Снова проверяем отмену после тяжелой операции
guard !isCancelled else {
outputResult = nil
return
}
}
private func processData(_ data: Data) -> Result { /* ... */ }
}
Пример использования с зависимостями и очередью:
// 1. Создаем операции
let downloadOp = BlockOperation { /* Загрузка данных */ }
let parseOp = DataProcessingOperation(data: Data())
let cacheOp = BlockOperation { /* Кэширование результата */ }
// 2. Определяем зависимости: parseOp ждет downloadOp, cacheOp ждет parseOp
parseOp.addDependency(downloadOp)
cacheOp.addDependency(parseOp)
// 3. Создаем и настраиваем очередь
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2 // Не более 2 операций одновременно
queue.qualityOfService = .userInitiated
// 4. Добавляем операции. Они выполнятся в порядке, заданном зависимостями.
queue.addOperations([downloadOp, parseOp, cacheOp], waitUntilFinished: false)
// 5. Можно отменить все операции в очереди
// queue.cancelAllOperations()
Когда использовать? NSOperation идеален для сложных, управляемых задач с четкими состояниями и зависимостями (например, цепочки загрузки и обработки). Для простых фоновых задач часто достаточно GCD.