async/await, the foundationswift-6.4/ios-26
Lesson 1 / 9
Unit 2 · Strict concurrency

async/await, the foundation

Coming from
Note

Unit 2 · Strict Concurrency. This unit is deliberately early and long: data-race safety is the #1 thing 2026 iOS interviews probe, so Segue treats it as a core module, not an appendix.

Modern Swift concurrency starts with two keywords. async marks a function that may suspend; await marks the point where a caller waits for it. Together they let you write asynchronous code that reads top-to-bottom like ordinary code — no nested callbacks, no completion handlers.

Declaring and calling

func loadUser(id: Int) async -> String {
    // …some awaited work…
    "user-\(id)"
}

// Calling it — the await is required and visible:
let name = await loadUser(id: 42)

await is a suspension point: the function may pause there, let other work run, then resume with the result. Crucially it does not block a thread the way a synchronous wait would — the thread is freed to do other work while you're suspended. That's why thousands of async tasks can share a small thread pool.

Note

await does not mean "this is slow" — it means "state may change while I'm paused here." After an await, don't assume anything you read before it is still true; re-check what matters. This is the mental discipline the visible suspension points are there to support.

Asynchrony is contagious (and that's good)

A function that calls an async function must itself be async. The colour spreads up the call chain until it reaches a boundary that can start async work: a Task, a SwiftUI .task modifier, or an @main entry point.

// Bridging from a synchronous context (e.g. a button action):
Button("Load") {
    Task {
        let name = await loadUser(id: 1)
        print(name)
    }
}

Task { … } creates a new top-level task that runs the async work. In SwiftUI you'll more often use .task { } on a view, which also ties the work's lifetime to the view's.

Coming from Kotlin

Swift's async/await maps closely to Kotlin suspend functions. Task { } is the rough analogue of launching in a coroutine scope, and structured concurrency (next lesson) mirrors coroutineScope { }. The big difference lands in Unit 2.5: Swift's Sendable checking is enforced by the compiler, not left to discipline.

Your turn

Await an async call and shape its result.

Await and transform an async result
Edit the code on the right, then run the hidden tests.

Knowledge check

Q: Does await block the current thread? No. It suspends the task and frees the thread for other work; the task resumes later. This is what lets async code scale far past the number of OS threads.

Q: You call an async function from a plain synchronous function and it won't compile. What's the fix? Start a Task { } (or make the caller async and push the boundary up). Something has to create the asynchronous context.

Solution.swiftSwift Testing
ConsoleReady · runs in a sandboxed Swift container
Press Run to compile against the hidden test suite.