Task Queues in Swift: GCD, OperationQueue and Combine for iOS/macOS

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 for Swift (iOS/macOS): Complete Guide



In iOS and macOS development, efficient management of threads and task queues is key to creating responsive and performant applications. Swift offers several powerful tools for working with asynchrony: from the classic Grand Central Dispatch (GCD) to the modern async/await model and the Combine framework. In this article, we will cover the main approaches, their features, and usage examples.



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



GCD is Apple's low-level library for managing parallel code execution. The main element is DispatchQueue, which can be serial or concurrent.



Main queues:

  • main — the main queue (UI thread). All interface updates must be performed on it.
  • global — system concurrent queues with different priorities (background, utility, default, userInitiated, userInteractive).
  • custom — user-created queues via DispatchQueue(label:attributes:).


Example: loading an image in the background

import UIKit

class ImageLoader { func loadImage(from url: URL, completion: @escaping (UIImage?) -> Void) { DispatchQueue.global(qos: .background).async { guard let data = try? Data(contentsOf: url), let image = UIImage(data: data) else { DispatchQueue.main.async { completion(nil) } return } DispatchQueue.main.async { completion(image) } } }}


2. OperationQueue — flexible task management



OperationQueue is a higher-level abstraction over GCD. It allows creating dependencies between operations, setting the maximum number of concurrent tasks, and canceling operations.



Key features:

  • Creating BlockOperation or custom subclasses of Operation.
  • Setting dependencies: operation2.addDependency(operation1).
  • Canceling all operations: queue.cancelAllOperations().
  • Quality of service control.


Example: sequential file download

import Foundation

let queue = OperationQueue()queue.maxConcurrentOperationCount = 1 // sequential execution

let fetchMetadata = BlockOperation { print("Loading metadata...") Thread.sleep(forTimeInterval: 1)}

let downloadContent = BlockOperation { print("Loading content...") Thread.sleep(forTimeInterval: 2)}

downloadContent.addDependency(fetchMetadata)

queue.addOperations([fetchMetadata, downloadContent], waitUntilFinished: false)print("Operations queued")


3. Swift Concurrency (async/await) — modern approach



Starting with Swift 5.5, Apple introduced a built-in asynchrony model with the async and await keywords. It allows writing asynchronous code linearly, without closures and callbacks.



Main components:

  • async — marking an asynchronous function.
  • await — waiting for the result of an asynchronous operation.
  • Task — creating an asynchronous context.
  • TaskGroup — grouping parallel tasks.


Example: parallel data loading

import Foundation

func fetchUser(id: Int) async -> String { // Simulating a network request try? await Task.sleep(nanoseconds: 1_000_000_000) return "User_\\(id)"}

func loadAllUsers() async { await withTaskGroup(of: String

Recommendations