Task Queues in Swift: GCD, OperationQueue and Swift Concurrency

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Task Queues in Swift: from GCD to Swift Concurrency



In iOS and macOS development, managing parallel code execution is one of the key tasks. Task queues allow you to efficiently distribute load across threads without blocking the user interface. In this guide, we will cover three main approaches: classic Grand Central Dispatch (GCD), the OperationQueue abstraction, and the modern Swift Concurrency mechanism (async/await).



1. Grand Central Dispatch (GCD) — the foundation of parallelism



GCD is a low-level C library integrated into Swift. It manages a thread pool and provides two types of queues:



  • Serial — tasks execute one after another in the order they are added.
  • Concurrent — tasks start simultaneously, completion order is not guaranteed.


Example of creating and using a queue:



import Foundation

// Create a serial queuelet serialQueue = DispatchQueue(label: "com.example.serial")

serialQueue.async { print("Task 1 started") sleep(1) print("Task 1 completed")}

serialQueue.async { print("Task 2 started") sleep(1) print("Task 2 completed")}

// Concurrent queuelet concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)

concurrentQueue.async { print("Concurrent task A")}

concurrentQueue.async { print("Concurrent task B")}


Key GCD features:

  • DispatchQueue.main — the main queue (UI thread).
  • DispatchQueue.global(qos: .userInitiated) — global queues with priority (QoS).
  • dispatchGroup — synchronization of multiple tasks.
  • dispatchSemaphore — controlling access to resources.


2. OperationQueue — object-oriented abstraction



OperationQueue is built on top of GCD but provides a higher-level API. Main advantages:



  • Managing dependencies between operations.
  • Canceling tasks (cancel).
  • State monitoring (isFinished, isExecuting).
  • Maximum number of concurrent operations.


Example using BlockOperation:



import Foundation

let operationQueue = OperationQueue()operationQueue.maxConcurrentOperationCount = 2

let operation1 = BlockOperation { print("Operation 1: loading data") sleep(2) print("Operation 1 completed")}

let operation2 = BlockOperation { print("Operation 2: processing") sleep(1) print("Operation 2 completed")}

// Set dependency: operation 2 will start only after operation 1 completesoperation2.addDependency(operation1)

operationQueue.addOperations([operation1, operation2], waitUntilFinished: false)

// Cancel operationoperation1.cancel()


When to use OperationQueue:

  • Complex task chains with dependencies.
  • Need for fine-grained control (pause, cancel).
  • Working with KVO (Key-Value Observing) for monitoring.


3. Swift Concurrency — modern approach (iOS 13+, macOS 10.15+)



Starting with Swift 5.5, Apple introduced built-in support for asynchronous programming through async/await, Task, and TaskGroup. This is a safer and more readable way to work with concurrency.



Basic example:



import Foundation

func fetchUserData() async -> String { // Simulate network request try? await Task.sleep(nanoseconds: 2 * 1_000_000_000) return "User data loaded"}

func processData()

Recommendations