Concurrency
Actors, isolation, Sendable, structured concurrency, and the Swift 6 rules that trip people up.
- Swift 6, can @MainActor do async work?Yes. Actor isolation controls where synchronous code runs, not whether it can suspend, so a @MainActor function can be async and await freely.
- Task vs Task.detached, and what is actor reentrancy?Task inherits the caller's actor context while Task.detached does not, and actors are reentrant at await points, so state can change mid-suspension.
- What does @concurrent do?@concurrent forces a function onto the background executor, opting out of Swift 6.2's new default where nonisolated async inherits the caller's actor.
- What is nonisolated(nonsending)?nonisolated(nonsending) keeps an async function on its caller's actor instead of hopping to the global executor, avoiding extra Sendable requirements.
- What is the difference between sending and consuming?consuming governs local ownership and lifetime on a single thread, while sending proves a value has no other references so it can safely cross actors.
- How does Swift enforce (or not enforce) thread safety?Swift proves data-race freedom at compile time through actor isolation and Sendable checking, but it can't catch reentrancy bugs or @unchecked escapes.
- What are Swift concurrency isolation rules?Two invariants govern isolation: you can't touch actor-isolated state off that actor, and you can't move a value across domains unless it's Sendable.
- Why is Sendable important?Sendable is how the compiler proves a value can cross isolation boundaries safely, turning whole classes of data race into compile-time errors.
- How does ARC interact with Swift concurrency?ARC has always used atomic retain and release since objects could cross threads, but it only keeps memory valid — Sendable is what makes contents safe.
- When do you still use GCD over async/await?GCD still earns its place for legacy callback APIs, DispatchGroup's heterogeneous waiting, and precise QoS control, not to dodge Sendable errors.
- How do you handle long-running tasks?Foreground work gets a Task with cancellation checks and progress reporting, while backgrounding needs BGTaskScheduler or a background URLSession.
- How do you prevent deadlocks?Avoid blocking a thread while holding a lock, never mix semaphores with async/await, and keep lock ordering consistent across call sites.
- How do you manage Core Data concurrency?Every NSManagedObjectContext is confined to its own queue, so access goes through perform, and objects cross contexts only by NSManagedObjectID.
- What is priority inversion?Priority inversion happens when a high-priority task waits on a lock held by a low-priority one that medium-priority work keeps preempting.
- Is @MainActor the same as the main thread?@MainActor is the compile-time guarantee whose executor schedules onto the main thread — the runtime resource UI frameworks actually require.
- What is withThrowingDiscardingTaskGroup?The throwing, result-discarding task group for long-lived supervisors — fail-fast on error, Void-only results, no way to observe individual completions.