Introduced in Swift 5.5, Swift’s built-in concurrency system provides a lightweight, yet highly efficient set of tools for writing concurrent code.
That all starts with
async/await, a pattern that’s become increasingly popular among modern programming languages, which enables us to utilize the language itself to manage long-running, asynchronous operations that are executed in the background. But that’s just the beginning.
The resources featured in this Discover guide will give you an introduction to the various tools and language features that Swift’s concurrency system ships with. They also contain lots of practical examples and techniques that can be useful to keep in mind when starting to adopt the concurrency system within various projects.
Task represents a unit of asynchronous work, and gives us access to a concurrent context in which we can call
async-marked APIs to perform various operations in the background. Let’s start by exploring what role that tasks play within Swift’s concurrency system, and how we can manage their execution in terms of delays and timing:
A very common type of situation in which parallelism and concurrent code can become especially useful is when we want to perform a set of operations for each element within a collection. The following articles illustrate a few different ways to do just that when using Swift’s concurrency system:
Although Swift’s concurrency system is, by itself, backward compatible all the way back to iOS 13, macOS Catalina, and the rest of Apple’s operating systems released in 2019 — we still very likely need to do some amount of work to make those new features compatible with our own code.
We might also need to manually make certain
async-marked system APIs backward compatible as well, as it’s just the language features themselves that are automatically compatible with earlier OS versions. So let’s take a look at how to write those kinds of bridges between the concurrency system and other Swift code:
Now, let’s move on to actors, which provide a built-in way to serialize how some piece of state is accessed and mutated — which in turn can help prevent concurrent memory issues, such as data races. Let’s take a look at how actors work, how to declare new
actor types, and how the
MainActor also provides a way for us to automatically dispatch UI-related code on the main thread:
Writing unit tests that verify asynchronous code can often be quite challenging — especially when such code involves networking, system services, or other logic that needs to be mocked in order for our code to become fully testable.
Thankfully, Swift’s concurrency system makes async testing much simpler, as Apple’s XCTest framework now features built-in support for
async-marked test functions. Let’s take a much closer look at that, as well as how
async/await could even help us make our code more testable to begin with, in these articles:
When adopting Swift Concurrency, we’ll also likely want to integrate it with other Apple frameworks — such as SwiftUI and Combine. Let’s take a look at a few quick examples of doing just that:
Want to learn more about how Swift’s concurrency system was developed, and how people are starting to use it within different context? Then have a listen to the following podcast episodes, which contain in-depth discussions about those exact topics:
Doug Gregor from Apple gives an introduction to Swift’s concurrency system
Tim Condon on how Swift Concurrency could impact the server-side Swift world
Marin Todorov shares his initial experiences and learnings from using Swift’s concurrency system
Chris Lattner on the evolution of the concurrency system, from the initial set of ideas to the implementation