Swift Concurrency introduces a structured, safe, and highly performant model for writing asynchronous and parallel code. Built directly into the Swift compiler and runtime, it eliminates common data races at compile time using actor isolation and cooperative task scheduling. Instead of relying on complex delegate callbacks or deeply nested completion handler closures, you write asynchronous code sequentially using `async` and `await`, making code easier to read, maintain, and reason about.
The model is built on three pillars: async/await syntax, structured tasks, and actors. Functions marked with `async` can suspend execution without blocking their underlying OS thread, letting other tasks run on the cooperative thread pool. These tasks are organized hierarchically in parent-child relationships under structured concurrency, ensuring that resources, cancellation, and errors propagate reliably. Mutable state is protected from data races by `Actor`s, which serialize access to their internal properties using compiler-enforced isolation.
Beyond basic task creation, Swift Concurrency provides rich mechanisms for processing streams of data and managing time. Types conforming to `AsyncSequence` emit values asynchronously over time, allowing you to iterate over them using `for await in` loops. The `Clock` protocol and its concrete implementations, `ContinuousClock` and `SuspendingClock`, allow you to measure elapsed time and suspend tasks. When integrating legacy callback-based APIs, continuations like `CheckedContinuation` act as a bridge, letting you suspend and resume async operations safely.
Get started
Protect mutable state with an Actor and run parallel tasks using a TaskGroup
import Foundation
// An actor isolates its state to prevent concurrent data races.
actor BankAccount {
private var balance: Double = 0.0
func deposit(amount: Double) {
balance += amount
}
func getBalance() -> Double {
return balance
}
}
// Create a bank account instance
let account = BankAccount()
// Perform concurrent operations using structured concurrency (TaskGroup)
try await withThrowingTaskGroup(of: Void.self) { group in
for _ in 1...100 {
group.addTask {
// Must await because account state is isolated to the actor
await account.deposit(amount: 10.0)
}
}
try await group.waitForAll()
}
let finalBalance = await account.getBalance()
print("Final balance: \(finalBalance)") // Safely prints 1000.0Key concepts
Cooperative Thread Pool
Swift Concurrency uses a global cooperative thread pool managed by the runtime. The pool scales its width to match the number of active CPU cores. Tasks yield control cooperatively when suspended (e.g., at `await` points), preventing thread explosion and minimizing context-switching overhead.
Structured Concurrency
Tasks are organized in a parent-child hierarchy. Using helper APIs like `async let` or `TaskGroup`, child tasks inherit traits like priority, task-local storage, and cancellation from their parent. This ensures that when a parent task is cancelled, all of its child tasks are automatically and recursively cancelled.
Actor Isolation & Data Safety
Actors are reference types that isolate their state from the outside world. Only one task can execute inside an actor at a time, eliminating data races. Code outside the actor must access its properties and methods asynchronously using `await`.
Data Race Safety & Sendable
To safely pass values across concurrency boundaries (between actors or threads), types must conform to the `Sendable` protocol. Sendable types are either immutable value types, actor types, or classes that implement internal synchronization.
Actor Isolation 3
Protocols and concepts that isolate mutable state to protect it from concurrent access, preventing data races at compile time.
- PrActoriOS 13.0+A protocol that defines a reference type that isolates its mutable state, ensuring that only a single thread can access its contents at any given time to prevent data races.nonisolated
actor Counter { private var value = 0 func increment() { value += 1 } } - PrGlobalActoriOS 13.0+A protocol that defines a globally unique actor (like `@MainActor`) that can be applied to classes, structures, functions, or properties to isolate their execution to a specific global thread/executor.sharedsharedExecutor
@globalActor actor MyGlobalActor { static let shared = MyGlobalActor() } - ClTaskLocaliOS 13.0+Wrapper type that defines a task-local value key.
Asynchronous Sequences 4
Represent and consume streams of values delivered over time asynchronously, using familiar sequences and streams.
- PrAsyncSequenceiOS 13.0+A protocol representing a stream of values that are produced asynchronously. Conforming types can be traversed sequentially using the `for await` syntax.makeAsyncIterator()
for await line in fileURL.lines { print(line) } - StAsyncStreamiOS 13.0+A concrete asynchronous sequence that produces elements from an interface that invokes a continuation callback. Perfect for wrapping delegate callbacks or notification streams.init(_:build:)Continuationyield(_:)finish()
let stream = AsyncStream(Int.self) { continuation in continuation.yield(1) continuation.finish() } - PrAsyncIteratorProtocoliOS 13.0+A type that asynchronously supplies the values of a sequence one at a
- StAsyncThrowingStreamiOS 13.0+An asynchronous sequence generated from an error-throwing closure that
Transforming Asynchronous Sequences 8
Standard operators and sequence types that allow you to map, filter, drop, or limit asynchronous sequences sequentially.
- StAsyncMapSequenceiOS 13.0+An asynchronous sequence that maps the given closure over the asynchronous
- StAsyncCompactMapSequenceiOS 13.0+An asynchronous sequence that maps a given closure over the asynchronous
- StAsyncFilterSequenceiOS 13.0+An asynchronous sequence that contains, in order, the elements of
- StAsyncFlatMapSequenceiOS 13.0+An asynchronous sequence that concatenates the results of calling a given
- StAsyncDropFirstSequenceiOS 13.0+An asynchronous sequence which omits a specified number of elements from the
- StAsyncDropWhileSequenceiOS 13.0+An asynchronous sequence which omits elements from the base sequence until a
- StAsyncPrefixSequenceiOS 13.0+An asynchronous sequence, up to a specified maximum length,
- StAsyncPrefixWhileSequenceiOS 13.0+An asynchronous sequence, containing the initial, consecutive
Throwing Sequence Operations 6
Sequence transformations that can throw errors during iteration, providing safe error propagation for streams.
- StAsyncThrowingMapSequenceiOS 13.0+An asynchronous sequence that maps the given error-throwing closure over the
- StAsyncThrowingCompactMapSequenceiOS 13.0+An asynchronous sequence that maps an error-throwing closure over the base
- StAsyncThrowingFilterSequenceiOS 13.0+An asynchronous sequence that contains, in order, the elements of
- StAsyncThrowingFlatMapSequenceiOS 13.0+An asynchronous sequence that concatenates the results of calling a given
- StAsyncThrowingDropWhileSequenceiOS 13.0+An asynchronous sequence which omits elements from the base sequence until a
- StAsyncThrowingPrefixWhileSequenceiOS 13.0+An asynchronous sequence, containing the initial, consecutive
Bridging Callbacks 1
Bridges completion-handler or delegate-based callbacks into the modern async/await model using checked continuations.
- StCheckedContinuationiOS 13.0+A safe mechanism for wrapping completion-handler-based asynchronous APIs, letting you suspend execution and resume it later. Enforces correctness by checking that the continuation is resumed exactly once.resume(returning:)resume(throwing:)resume(with:)
try await withCheckedThrowingContinuation { continuation in legacyFetch { result, error in if let error = error { continuation.resume(throwing: error) } else { continuation.resume(returning: result) } } }
Executors and Scheduling 4
Mechanisms to control where and how concurrent tasks run, scheduling work onto custom or serial executors.
- StTaskPriorityiOS 13.0+Represents the relative importance and scheduling urgency of a task, mapped internally to system QoS levels like user-interactive or background..high.medium.low.background.utility.userInitiated
Task(priority: .background) { print("Running on low priority thread") } - PrExecutoriOS 13.0+A service that can execute jobs.
- PrSerialExecutoriOS 13.0+A service that executes jobs.
- PrTaskExecutoriOS 18.0+An executor that may be used as preferred executor by a task.
Clocks 3
Measures elapsed time and suspends execution for specific durations using continuous or suspending time bases.
- StContinuousClockiOS 16.0+A clock that measures time continuously, including time when the CPU/system is asleep. The ideal choice for measuring human-perceived execution time or timeouts.nowsleep(until:tolerance:)measure(_:)
let clock = ContinuousClock() let duration = try await clock.measure { try await Task.sleep(for: .seconds(2)) } - PrClockiOS 16.0+A mechanism in which to measure time, and delay work until a given point
- StSuspendingClockiOS 16.0+A clock that measures time that always increments but stops incrementing
Cancellation and Task Inspection 2
Inspects metadata of the currently executing task or handles cooperative cancellation requests cleanly.
- StUnsafeCurrentTaskiOS 13.0+A lightweight structure representing the currently executing task, allowing you to check for cancellation or inspect task-local values in synchronous contexts.isCancelledprioritycancel()
if let task = withUnsafeCurrentTask { print("Priority is \(task.priority)") } - StCancellationErroriOS 13.0+An error that indicates a task was canceled.
Structures 12
- StDiscardingTaskGroupiOS 17.0+A discarding group that contains dynamically created child tasks.
- StExecutorJobiOS 17.0+A unit of schedulable work.
- StJobDeprecated equivalent of ``ExecutorJob``.
- StJobPriorityiOS 17.0+The priority of this job.
- StTaskiOS 13.0+A unit of asynchronous work that runs concurrently. You use `Task` to start unstructured concurrency, inheritance of priorities, and lifecycle control.init(priority:operation:)initDetached(priority:operation:)valuecancel()isCancelledsleep(for:)
let task = Task { return try await fetchSomething() } let result = try await task.value - StTaskGroupiOS 13.0+A group that manages a dynamic number of concurrent child tasks under a structured parent-child relationship. Created using the `withTaskGroup` or `withThrowingTaskGroup` functions.addTask(priority:operation:)next()isEmptywaitForAll()cancelAll()
try await withThrowingTaskGroup(of: Int.self) { group in group.addTask { 1 } group.addTask { 2 } while let value = try await group.next() { ... } } - StThrowingDiscardingTaskGroupiOS 17.0+A throwing discarding group that contains dynamically created child tasks.
- StThrowingTaskGroupiOS 13.0+A group that contains throwing, dynamically created child tasks.
- StUnownedJobiOS 13.0+A unit of schedulable work.
- StUnownedSerialExecutoriOS 13.0+An unowned reference to a serial executor (a `SerialExecutor`
- StUnownedTaskExecutoriOS 18.0+
- StUnsafeContinuationiOS 13.0+A mechanism to interface
Actors 1
- AcMainActoriOS 13.0+A globally unique actor that represents the main execution thread, typically used to isolate UI updates and view models in graphical applications.sharedrun(resultType:body:)
@MainActor func updateUI() { self.label.text = "Loaded" }
Type Aliases 3
- TyAnyActorCommon marker protocol providing a shared "base" for both (local) `Actor`
- TyPartialAsyncTask
- TyUnsafeThrowingContinuation