How Do I Write Concurrent Swift?

This resource is mainted by Tuist on GitHub, licensed under CC BY-NC-SA, and draws is inspired by How Do I Write If Case Let in Swift? and How Do I Declare A Block in Objective-C?. We love simplifying complexity, and this resource empowers Swift developers to master concurrency. If you find it helpful, sharing it would greatly motivate us to keep building for the community.

Concurrency and Parallelism

Modern Apple devices (like Vision Pros, iPhones, and MacBooks) have multiple cores, allowing tasks to run at the same time—this is called parallelism. This is different from concurrency, where tasks overlap in execution but may not run at exactly the same time.

Throughout this page, we'll use 'concurrency' to refer to both concurrency and parallelism.

Value

Concurrency can improve your software’s performance.

Challenges

Making your software concurrent has its challenges:

  1. Readability: Writing concurrent code that's easy to understand.
  2. Safety: Swift allows mutable data, so concurrent tasks might try to change the same data at the same time, leading to crashes (data races). Avoiding this is crucial.
  3. Deadlocks: When two tasks wait on each other, causing them both to stop.
  4. Performance: Ensuring your concurrent code runs efficiently.

IO-bound and CPU-bound Code

It's key to understand the difference between IO-bound and CPU-bound code:

Many apps are IO-bound, often waiting for server data to update the UI or for database queries to complete before sending an HTTP response.

Note

CPU-bound code is generally harder to optimize than IO-bound code. CPU optimizations may require significant changes to data structures and logic, while IO optimizations often involve reorganizing tasks to run concurrently.

Swift

Enough theory—let’s dive into concurrency in Swift. There are several ways to write concurrent code, and the following sections will guide you through each, from the oldest legacy options to the latest modern approaches. We’ll also provide simple guidelines to help you choose the best option for your use case.

Threading

Grand Central Dispatch (GCD)

Operation and OperationQueue

Structured Concurrency

Actors

AsyncStream and AsyncSequence