OperationQueue — что это такое, Operation и управление задачами

Автор: IT Sectr Опубликовано: 2026-03-16 Время чтения: 8 мин

OperationQueue — это высокоуровневая очередь задач в iOS и macOS, построенная поверх Grand Central Dispatch. По данным Apple Developer Documentation, 2026, OperationQueue управляет экземплярами Operation — объектами, инкапсулирующими единицу работы. В отличие от DispatchQueue, OperationQueue поддерживает зависимости между операциями, приоритеты, KVO-наблюдение и отмену запущенных задач. OperationQueue автоматически управляет пулом потоков, распределяя операции по доступным ресурсам системы.

Главное

  • OperationQueue — высокоуровневая очередь с поддержкой зависимостей между операциями
  • Operation — абстрактный класс для инкапсуляции единицы работы с состоянием
  • BlockOperation — упрощённая реализация Operation для одного блока кода
  • Зависимости определяют порядок выполнения: операция B запускается после A
  • Отмена операций поддерживается через KVO-совместимое свойство isCancelled

Что такое OperationQueue и Operation

OperationQueue — это класс из фреймворка Foundation, управляющий выполнением объектов Operation. В отличие от DispatchQueue, OperationQueue не требует явного указания serial или concurrent режима — количество одновременно выполняющихся операций регулируется свойством maxConcurrentOperationCount. Значение 1 превращает очередь в sequential, любое другое — в concurrent.

Operation — абстрактный класс, представляющий единицу работы. Каждая операция имеет состояние: ready, executing, finished или cancelled. Состояния совместимы с KVO (Key-Value Observing), что позволяет реагировать на изменения — например, обновлять UI при завершении операции. Operation автоматически управляет флагами isExecuting и isFinished.

По данным Apple (2026), OperationQueue использует GCD под капотом, но добавляет функциональность, недоступную в DispatchQueue: зависимости, приоритеты и отмена операций. Если приложение выходит на фоновый режим, OperationQueue приостанавливает выполнение, а при возвращении — возобновляет. OperationQueue также автоматически учитывает количество ядер процессора и выбирает оптимальное количество потоков.

Жизненный цикл Operation

Каждая операция проходит через четыре состояния: pending (ожидание), ready (готова к запуску), executing (выполняется) и finished (завершена). Состояние cancelled может наступить на любом этапе до завершения. Переходы между состояниями отслеживаются через KVO — это основа для реактивного обновления UI. OperationQueue автоматически удаляет завершённые операции из очереди и уведомляет зависимые операции о том, что их prerequisite выполнен, запуская их выполнение.

Operation и BlockOperation: реализация задач

Operation — абстрактный класс, требующий переопределения метода main() или start(). В методе main() размещается код задачи, а состояние isExecuting и isFinished управляются автоматически. Для асинхронных операций требуется переопределить start() и вручную управлять флагами состояния.

BlockOperation — конкретная реализация Operation, выполняющая один или несколько блоков кода. BlockOperation становится concurrent, если добавить в неё несколько блоков через addExecutionBlock(). Завершается операция только после выполнения всех добавленных блоков. BlockOperation — удобная альтернатива для простых задач без наследования.

ХарактеристикаOperationBlockOperation
Тип классаАбстрактныйКонкретный
НаследованиеТребуетсяНе требуется
АсинхронностьРучное управление KVOАвтоматическое
Блоков кодаОдин в main()Один или несколько
ПрименениеСложные задачи с состояниемПростые однократные задачи
Подходит дляЗависимости, отмена, прогрессБыстрые блоки, completion
ПамятьВыше из-за KVO и состоянияМинимальная, легковесная

Создание собственной Operation

Для создания кастомной операции наследуйтесь от Operation и переопределите main(). Внутри проверяйте флаг isCancelled перед дорогими операциями, чтобы обеспечить быструю отмену. Это критично для загрузки больших файлов или пакетной обработки данных. Выбор между Operation и BlockOperation зависит от сложности задачи: для простых однократных действий достаточно BlockOperation, для переиспользуемой логики с состоянием — наследование от Operation.

Зависимости и приоритеты операций

Зависимости — ключевое преимущество OperationQueue перед DispatchQueue. Метод addDependency(_:) определяет, что операция B выполняется только после завершения операции A. Зависимости образуют directed acyclic graph (DAG): при добавлении циклической зависимости очередь игнорирует её, и операции не запускаются.

Приоритет операции задаётся свойством queuePriority со значениями: .veryLow, .low, .normal, .high, .veryHigh. Приоритет влияет на порядок запуска среди ready-операций, но не отменяет зависимости. OperationQueue сначала учитывает зависимости, затем — приоритет среди доступных операций.

Практический пример зависимостей

Типичный сценарий — загрузка данных профиля: сначала загружаем пользователя, затем на основе его id загружаем друзей и посты. Установка зависимости между загрузкой пользователя и загрузкой друзей гарантирует корректный порядок без вложенных completion handler.

Ограничение параллелизма

Свойство maxConcurrentOperationCount ограничивает количество одновременно выполняемых операций. Значение 1 создаёт sequential очередь, значение по умолчанию (NSOperationQueueDefaultMaxConcurrentOperationCount) — системно-оптимальное, зависящее от текущей нагрузки устройства. Правильная настройка этого параметра предотвращает чрезмерное потребление ресурсов: для загрузки изображений достаточно 4-6 concurrent операций, для CPU-интенсивных задач — количество ядер процессора.

OperationQueue vs DispatchQueue: сравнение

Выбор между OperationQueue и DispatchQueue зависит от сложности задачи. DispatchQueue — лёгковесный инструмент для простых async-вызовов. OperationQueue — более тяжёлое решение для сложных сценариев с множеством взаимосвязанных задач. Apple рекомендует начинать с DispatchQueue и переходить на OperationQueue только при необходимости зависимостей или отмены. Для большинства iOS-проектов комбинация обоих инструментов даёт оптимальный баланс производительности и гибкости.

  • DispatchQueue — лёгкая, быстрая, без накладных расходов на объекты Operation
  • OperationQueue — поддерживает зависимости, отмену, KVO и приоритеты
  • DispatchQueue — идеальна для простых async/asyncAfter задач и синхронизации через serial
  • OperationQueue — незаменима при пошаговых алгоритмах с последовательными этапами
  • DispatchQueue — интеграция с Swift Concurrency (async/await) через Continuation

По данным Ray Wenderlich (2025), в крупных iOS-проектах OperationQueue используется для загрузки контента с прогрессом и отменой, а DispatchQueue — для всех остальных async-операций. Соотношение примерно 20 к 80 в пользу DispatchQueue.

Примеры кода с OperationQueue в Swift

Рассмотрим три примера: простой BlockOperation, кастомная Operation с зависимостями и отменяемая операция для загрузки данных.

BlockOperation с completion

Самый простой случай — выполнить блок на OperationQueue и обработать результат через completionBlock. Каждая Operation имеет встроенное свойство completionBlock, вызываемое после завершения main().

swift
let queue = OperationQueue()
let operation = BlockOperation()
operation.addExecutionBlock {
    let data = NetworkService.fetchData()
    OperationQueue.main.addOperation {
        self.updateUI(data)
    }
}
queue.addOperation(operation)

Зависимости между операциями

Зависимость гарантирует, что parseOperation запустится только после завершения downloadOperation. Это устраняет необходимость во вложенных callback.

swift
let download = BlockOperation { self.downloadJSON() }
let parse = BlockOperation { self.parseJSON() }
parse.addDependency(download)

let queue = OperationQueue()
queue.addOperations([download, parse], waitUntilFinished: false)

Отменяемая кастомная Operation

Переопределите main() с периодической проверкой isCancelled. Это позволяет немедленно остановить операцию при отмене, не дожидаясь завершения дорогой операции.

swift
class ImageLoadOperation: Operation {
    override func main() {
        guard !self.isCancelled else { return }
        let image = self.downloadImage()
        guard !self.isCancelled else { return }
        OperationQueue.main.addOperation { self.display(image) }
    }
}

Отмена операций и KVO-наблюдение

Отмена операции устанавливает флаг isCancelled в true, но не останавливает уже запущенный метод main(). Код внутри main() должен самостоятельно проверять isCancelled и завершаться при необходимости. Это архитектурное решение Apple — позволяющее разработчику корректно освободить ресурсы при отмене.

KVO-наблюдение за свойствами isFinished и isExecuting позволяет реагировать на завершение операций без explicit callback. OperationQueue автоматически удаляет завершённые операции из очереди, но они сохраняются в памяти до тех пор, пока на них есть сильные ссылки. KVO — основа для интеграции OperationQueue с реактивными фреймворками типа RxSwift или Combine.

Обработка отмены через KVO

Подписка на isCancelled через KVO позволяет обновлять UI при отмене операции — например, показывать placeholder вместо отменённой загрузки. Свойство isCancelled является KVO-совместимым, что делает его удобным для реактивных pipeline.

Лучшие практики работы с OperationQueue

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

Проверяйте isCancelled перед дорогими операциями внутри метода main(). В случаях загрузки файлов или обработки изображений проверка после каждого значимого шага обеспечивает быстрый отклик на отмену. Используйте if isCancelled { return } в начале main() и после каждой крупной операции.

Правильно управляйте completionBlock. Свойство completionBlock операции вызывается после завершения main(), даже если операция была отменена. Проверяйте isCancelled внутри completionBlock, чтобы не обновлять UI ошибочными данными. OperationQueue.main — потокобезопасная очередь для UI-операций, аналогичная DispatchQueue.main.

Избегайте циклических зависимостей — они приводят к тому, что ни одна из операций в цикле никогда не запустится. OperationQueue не детектирует циклы автоматически: если A зависит от B, а B зависит от A, обе навсегда останутся в состоянии ready. Планируйте граф зависимостей заранее.

Часто задаваемые вопросы

Чем OperationQueue отличается от DispatchQueue?

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

Как сделать очередь последовательной?

Установите свойство maxConcurrentOperationCount в 1. Это превращает OperationQueue в sequential очередь с сохранением всех преимуществ — зависимостей, приоритетов и отмены.

Можно ли отменить запущенную операцию?

Метод cancel() устанавливает флаг isCancelled, но не останавливает выполняющийся метод main(). Код операции должен сам проверять isCancelled и завершаться. Отмена работает только для pending и ready операций.

Когда стоит использовать Operation вместо BlockOperation?

Операцию стоит наследовать, когда требуется управление состоянием, асинхронность или переиспользование логики. BlockOperation подходит для простых однократных задач без наследования.

Блокирует ли OperationQueue главный поток?

Нет, если не вызван метод waitUntilFinished с параметром true на главном потоке. Операции по умолчанию выполняются на фоновых потоках, а результат возвращается через OperationQueue.main.

Итоги

  • OperationQueue — высокоуровневая очередь с зависимостями, приоритетами и отменой операций
  • Operation — абстрактный класс для инкапсуляции работы с KVO-совместимым состоянием
  • BlockOperation — упрощённая реализация для одного или нескольких блоков кода
  • Зависимости задают порядок выполнения между операциями через граф без циклов
  • Отмена требует ручной проверки isCancelled внутри метода main() операции
  • maxConcurrentOperationCount = 1 превращает очередь в sequential режим
  • OperationQueue vs DispatchQueue — выбирайте OperationQueue только при необходимости зависимостей или KVO

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также