tezvyn:

How does Swift async/await improve on completion handlers?

AI-drafted, machine-checkedSource: docs.swift.orgadvanced

Tests structured concurrency mastery over callback control flow. A strong answer covers inversion of control, suspension points as yield locations, and Tasks as parent-child units.

WHAT THIS TESTS: Whether you understand the semantic shift from ad-hoc callbacks to structured concurrency. Interviewers want to see that you know async/await is not just cleaner syntax but a runtime contract involving cooperative scheduling, suspension, and task trees.

A GOOD ANSWER COVERS: Four things in order. First, completion handlers invert control and force manual state management across scattered callbacks, while async/await restores sequential top-to-bottom flow and makes error handling uniform via throws. Second, a suspension point is the exact spot marked by await where the current task voluntarily yields its thread back to the runtime without blocking the underlying thread, allowing other work to proceed while the async operation completes. Third, a Task is the fundamental unit of structured concurrency in Swift; it creates a concrete scope in which async work runs, enabling parent-child relationships so that cancelling a parent automatically cancels its children and awaiting a parent implicitly awaits all descendants. Fourth, structured concurrency guarantees that work started inside a scope cannot outlive that scope, preventing the orphaned callbacks and memory leaks common with completion handlers.

COMMON WRONG ANSWERS: Calling async/await mere syntactic sugar over closures misses the runtime and thread-model differences. Confusing a Task with a DispatchQueue or an OS thread shows misunderstanding of Swift's cooperative thread pool. Saying await blocks the thread is a critical error; suspension frees the thread. Forgetting that Task.init creates an unstructured task while TaskGroup and async let create structured parent-child trees is another frequent gap.

LIKELY FOLLOW-UPS: How does cancellation propagate through a task tree and how do you check for it inside an async function? When would you use an unstructured Task versus a TaskGroup? How does the runtime decide which thread to use after a suspension point resumes? What is the difference between a detached task and a child task regarding priority inheritance and cancellation?

ONE CONCRETE EXAMPLE: Imagine fetching a user profile and then their avatar. With completion handlers, you nest two data tasks and manually manage a cancellation flag or operation queue. With async/await, you write let profile = try await fetchUser followed by let avatar = try await fetchAvatar with profile.id. Each await is a suspension point. If both calls run inside a single Task launched from a view model, cancelling that Task automatically propagates cancellation to both network requests because they are part of the same structured scope.

Read the original → docs.swift.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.