OperationQueue — what it is, Operation and task management

Author: IT Sectr Published: 2026-03-16 Reading time: 8 min

OperationQueue is a high-level task queue in iOS and macOS built on top of Grand Central Dispatch. According to Apple Developer Documentation, 2026, OperationQueue manages instances of Operation — objects that encapsulate a unit of work. Unlike DispatchQueue, OperationQueue supports dependencies between operations, priorities, KVO observation, and cancellation of running tasks. OperationQueue automatically manages a thread pool, distributing operations across available system resources.

Key Takeaways

  • OperationQueue — a high-level queue with support for dependencies between operations
  • Operation — an abstract class for encapsulating a unit of work with state
  • BlockOperation — a simplified implementation of Operation for a single block of code
  • Dependencies define execution order: operation B runs after A completes
  • Cancellation of operations is supported through the KVO-compatible isCancelled property

What Is OperationQueue and Operation

OperationQueue is a class from the Foundation framework that manages the execution of Operation objects. Unlike DispatchQueue, OperationQueue does not require explicitly specifying serial or concurrent mode — the number of simultaneously executing operations is controlled by the maxConcurrentOperationCount property. A value of 1 makes the queue sequential, any other value makes it concurrent.

Operation is an abstract class representing a unit of work. Each operation has a state: ready, executing, finished, or cancelled. The states are KVO (Key-Value Observing) compatible, allowing you to react to changes — for example, updating the UI when an operation completes. Operation automatically manages the isExecuting and isFinished flags.

According to Apple (2026), OperationQueue uses GCD under the hood but adds functionality not available in DispatchQueue: dependencies, priorities, and cancellation of operations. If the app enters the background, OperationQueue suspends execution and resumes when it returns. OperationQueue also automatically considers the number of CPU cores and selects the optimal number of threads.

Operation Lifecycle

Each operation goes through four states: pending, ready, executing, and finished. The cancelled state can occur at any stage before completion. State transitions are tracked via KVO — this is the foundation for reactive UI updates. OperationQueue automatically removes completed operations from the queue and notifies dependent operations that their prerequisite has been fulfilled, triggering their execution.

Operation and BlockOperation: Implementing Tasks

Operation is an abstract class that requires overriding the main() or start() method. The task code is placed in the main() method, and the isExecuting and isFinished states are managed automatically. For asynchronous operations, you need to override start() and manually manage the state flags.

BlockOperation is a concrete implementation of Operation that executes one or more code blocks. BlockOperation becomes concurrent if you add multiple blocks via addExecutionBlock(). The operation completes only after all added blocks have finished. BlockOperation is a convenient alternative for simple tasks without inheritance.

CharacteristicOperationBlockOperation
Class TypeAbstractConcrete
InheritanceRequiredNot required
AsynchronicityManual KVO managementAutomatic
Code BlocksOne in main()One or many
UsageComplex tasks with stateSimple one-time tasks
Suitable forDependencies, cancellation, progressQuick blocks, completion
MemoryHigher due to KVO and stateMinimal, lightweight

Creating a Custom Operation

To create a custom operation, subclass Operation and override main(). Inside, check the isCancelled flag before expensive operations to ensure fast cancellation. This is critical for downloading large files or batch data processing. Choosing between Operation and BlockOperation depends on the task complexity: for simple one-time actions, BlockOperation is sufficient; for reusable logic with state, subclass Operation.

Dependencies and Priorities of Operations

Dependencies are the key advantage of OperationQueue over DispatchQueue. The addDependency(_:) method specifies that operation B executes only after operation A completes. Dependencies form a directed acyclic graph (DAG): if a cyclic dependency is added, the queue ignores it and the operations do not start.

Priority of an operation is set via the queuePriority property with values: .veryLow, .low, .normal, .high, .veryHigh. Priority affects the launch order among ready operations but does not override dependencies. OperationQueue first resolves dependencies, then applies priority among available operations.

Practical Example of Dependencies

A typical scenario is loading profile data: first load the user, then based on their id load friends and posts. Setting a dependency between loading the user and loading friends guarantees correct order without nested completion handlers.

Limiting Concurrency

The maxConcurrentOperationCount property limits the number of concurrently executing operations. A value of 1 creates a sequential queue, the default value (NSOperationQueueDefaultMaxConcurrentOperationCount) is system-optimal, depending on the current device load. Proper configuration of this parameter prevents excessive resource consumption: for image loading, 4–6 concurrent operations are sufficient; for CPU-intensive tasks, use the number of CPU cores.

OperationQueue vs DispatchQueue: Comparison

Choosing between OperationQueue and DispatchQueue depends on task complexity. DispatchQueue is a lightweight tool for simple async calls. OperationQueue is a heavier solution for complex scenarios with many interrelated tasks. Apple recommends starting with DispatchQueue and switching to OperationQueue only when dependencies or cancellation are needed. For most iOS projects, a combination of both tools provides an optimal balance of performance and flexibility.

  • DispatchQueue — lightweight, fast, without the overhead of Operation objects
  • OperationQueue — supports dependencies, cancellation, KVO, and priorities
  • DispatchQueue — ideal for simple async/asyncAfter tasks and serial synchronization
  • OperationQueue — indispensable for step-by-step algorithms with sequential stages
  • DispatchQueue — integrates with Swift Concurrency (async/await) via Continuation

According to Ray Wenderlich (2025), in large iOS projects, OperationQueue is used for content loading with progress and cancellation, while DispatchQueue is used for all other async operations. The ratio is approximately 20 to 80 in favor of DispatchQueue.

Code Examples with OperationQueue in Swift

Let us look at three examples: a simple BlockOperation, a custom Operation with dependencies, and a cancellable operation for data loading.

BlockOperation with Completion

The simplest case — execute a block on OperationQueue and handle the result via completionBlock. Every Operation has a built-in completionBlock property, called after main() finishes.

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

Dependencies Between Operations

Dependency ensures that parseOperation starts only after downloadOperation completes. This eliminates the need for nested callbacks.

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

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

Cancellable Custom Operation

Override main() with periodic isCancelled checks. This allows the operation to stop immediately upon cancellation, without waiting for an expensive operation to complete.

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) }
    }
}

Operation Cancellation and KVO Observation

Cancellation of an operation sets the isCancelled flag to true, but does not stop an already running main() method. The code inside main() must check isCancelled by itself and terminate when necessary. This is Apple's architectural decision — allowing the developer to properly release resources upon cancellation.

KVO observation of isFinished and isExecuting properties allows reacting to operation completion without explicit callbacks. OperationQueue automatically removes completed operations from the queue, but they remain in memory as long as there are strong references to them. KVO is the foundation for integrating OperationQueue with reactive frameworks like RxSwift or Combine.

Handling Cancellation via KVO

Subscribing to isCancelled via KVO allows updating the UI upon operation cancellation — for example, showing a placeholder instead of a cancelled download. The isCancelled property is KVO-compatible, making it convenient for reactive pipelines.

Best Practices for Working with OperationQueue

Do not create large numbers of operations — each Operation is a separate object in memory. If a task is short and does not require dependencies, use DispatchQueue directly. OperationQueue is justified for complex scenarios with explicit dependencies, cancellation, and progress monitoring.

Check isCancelled before expensive operations inside the main() method. In cases of file downloading or image processing, checking after each significant step ensures fast response to cancellation. Use if isCancelled { return } at the start of main() and after each major operation.

Manage completionBlock properly. The completionBlock property of an operation is called after main() finishes, even if the operation was cancelled. Check isCancelled inside completionBlock to avoid updating the UI with erroneous data. OperationQueue.main is a thread-safe queue for UI operations, similar to DispatchQueue.main.

Avoid cyclic dependencies — they cause none of the operations in the cycle to ever start. OperationQueue does not detect cycles automatically: if A depends on B and B depends on A, both will remain in the ready state forever. Plan the dependency graph in advance.

Frequently Asked Questions

How is OperationQueue different from DispatchQueue?

OperationQueue is built on top of GCD and adds dependencies, priorities, KVO, and operation cancellation. DispatchQueue is a lighter tool for simple async tasks without these capabilities.

How do I make the queue sequential?

Set the maxConcurrentOperationCount property to 1. This turns OperationQueue into a sequential queue while retaining all advantages — dependencies, priorities, and cancellation.

Can I cancel a running operation?

The cancel() method sets the isCancelled flag but does not stop the executing main() method. The operation code must check isCancelled by itself and terminate. Cancellation only works for pending and ready operations.

When should I use Operation instead of BlockOperation?

You should subclass Operation when you need state management, asynchronicity, or logic reuse. BlockOperation is suitable for simple one-time tasks without inheritance.

Does OperationQueue block the main thread?

No, unless you call waitUntilFinished with the parameter true on the main thread. Operations execute on background threads by default, and results are returned via OperationQueue.main.

Summary

  • OperationQueue — a high-level queue with dependencies, priorities, and operation cancellation
  • Operation — an abstract class for encapsulating work with KVO-compatible state
  • BlockOperation — a simplified implementation for one or more code blocks
  • Dependencies define execution order between operations through a cycle-free graph
  • Cancellation requires manual isCancelled checking inside the operation's main() method
  • maxConcurrentOperationCount = 1 turns the queue into sequential mode
  • OperationQueue vs DispatchQueue — choose OperationQueue only when dependencies or KVO are needed

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also