An actor caches a computed value: `func total() async -> Int { if let c = cache { return c }; let v = await recompute(); cache = v; return v }`. Under concurrent callers, what correctness problem exists?
- A. None — actor isolation serializes all access, so `cache` can never be read stale
- B. During the `await recompute()` suspension another task can enter the actor and also see `cache == nil`, causing redundant recomputes and a possible last-writer-wins overwrite ✓
- C. The compiler rejects it because `cache` is mutated inside an async method on an actor
- D. `recompute()` runs on a background thread, so `cache = v` is a data race the runtime will trap on
Correct answer: B. Actors are reentrant: at an `await` suspension point another task can run actor code, so the pre-await `cache == nil` check no longer holds and the invariant breaks.
A `struct Container { var items: [Int] }` uses copy-on-write via `Array`. You hold `var a = Container(...)`, do `let b = a`, then `a.items.append(1)`. What determines whether the append copies the backing buffer?
- A. It always copies because `let b = a` copies the whole struct including the array buffer eagerly
- B. It copies only if the `Array`'s storage is not uniquely referenced at mutation time — since `b` shares the buffer, `isKnownUniquelyReferenced` is false and it copies ✓
- C. It never copies because `a` and `b` are separate struct instances with independent buffers
- D. It copies only if `Container` is marked `@frozen`, otherwise the buffer is shared forever
Correct answer: B. COW defers duplication until mutation and copies only when the buffer's reference count shows it is shared, which it is because `b` still points at the same storage.
In SwiftUI, a parent view creates a child as `ChildView(model: MyModel())` where `ChildView` declares `@StateObject private var model`. The parent re-renders frequently. What happens to the `MyModel` instance?
- A. A fresh `MyModel` is created and adopted on every parent re-render, resetting the child's state
- B. The `MyModel()` in the initializer is evaluated on every re-render but `@StateObject` keeps the first instance and discards the newly created ones ✓
- C. `@StateObject` forbids passing an instance through the initializer; this fails to compile
- D. The child observes the parent's model by reference, so parent re-renders mutate it in place
Correct answer: B. `@StateObject`'s autoclosure runs each time the initializer is called but SwiftUI only uses the value from first appearance and keeps that instance stable, so the extra allocations are wasted but state is preserved.
Swift 6 flags: `final class Cache { var data: [String:Int] = [:] }` passed into `Task.detached { cache.data["x"] = 1 }`. Why the data-race diagnostic, and the correct minimal fix?
- A. `Cache` isn't `Sendable` because it has mutable non-isolated state; make it an `actor` (or add a lock and mark it `@unchecked Sendable`) ✓
- B. Add `@Sendable` to the closure — that alone makes the capture safe
- C. Mark `Cache` as `final` — it already is, so the error is a compiler bug you silence with `nonisolated`
- D. Change `var data` to `let data` — an immutable dictionary reference makes concurrent writes safe
Correct answer: A. A final class with mutable state is not `Sendable`; making it an actor gives isolated serialized access, whereas `@Sendable` on the closure or `let` on the reference does not protect the dictionary's contents from concurrent writes.
Given `protocol P { func f() -> String }` with `extension P { func f() -> String { "ext" }; func g() -> String { "g-" + f() } }` and `struct S: P { func f() -> String { "S" } }`. What does `(S() as P).g()` return?
- A. "g-ext" because `g` is only in the extension and calls the extension's `f`
- B. "g-S" because `f` is a protocol requirement, so it dispatches through the witness table to `S.f` ✓
- C. "g-ext" because calling through the existential `as P` erases the concrete type and uses defaults
- D. It is ambiguous and fails to compile due to two candidate `f` implementations
Correct answer: B. Because `f()` is declared in the protocol it is a requirement dispatched dynamically via the witness table to `S`'s override, so `g` (even from the extension) sees "S".
You register `NotificationCenter.default.addObserver(forName:object:queue:using:)` with a closure capturing `self`, in a UIViewController. What is the leak/behavior risk and best remedy?
- A. No risk — NotificationCenter uses weak references to observers automatically
- B. The block-based API retains the closure (and thus `self`); use `[weak self]` and/or remove the observer token in `deinit` ✓
- C. The controller leaks only if the notification never fires; firing it releases the closure
- D. Using `queue: .main` breaks the retain cycle by hopping threads
Correct answer: B. The block-based observer API strongly retains the closure until you remove the returned token, so capturing `self` strongly keeps the controller alive; capture weakly and remove the token.
A `Timer.scheduledTimer(withTimeInterval:repeats:true)` block captures `self` (a view controller). Even after the VC is dismissed it never deinits. Why, and which fix actually works?
- A. The run loop weakly holds the timer; add `[weak self]` and it will deinit immediately on dismiss
- B. The run loop retains the repeating timer, and the timer retains the closure retaining `self`; you must invalidate the timer (weak self alone won't stop the timer or free it) ✓
- C. `Timer` is `Sendable`, so it must be recreated on the main actor to break the cycle
- D. Setting `timer.tolerance` releases the closure between fires, breaking the retain cycle
Correct answer: B. The run loop keeps the repeating timer alive and the timer strongly holds its closure; `[weak self]` avoids the VC being kept alive but you still must `invalidate()` to stop and release the timer.
Comparing `func makeShape() -> some Shape` (opaque) vs `func makeShape() -> any Shape` (existential) for a factory returning one concrete `Circle`. Which statement is correct?
- A. `some Shape` erases the type at runtime and boxes it, while `any Shape` preserves the static type with no allocation
- B. `some Shape` pins one hidden concrete type known to the compiler (enabling static dispatch/specialization), while `any Shape` is a runtime box allowing heterogeneous returns at a dynamic-dispatch cost ✓
- C. They are interchangeable; `some` and `any` compile to identical code for a single concrete return
- D. `any Shape` cannot be returned from a function that has only one concrete return type
Correct answer: B. `some` guarantees one specific underlying type the compiler tracks (permitting specialization), whereas `any` is an existential box that supports differing dynamic types at the cost of indirection.
Two serial queues A and B. Code on A does `B.sync { ... }` while code on B does `A.sync { ... }` concurrently. What is the outcome, and what is the classic single-queue variant of this bug?
- A. A priority inversion that Instruments flags as a Hitch; the single-queue variant is calling `async` on the same queue
- B. A deadlock from cyclic `sync` waits; the single-queue variant is calling `queue.sync` from a block already running on that same serial queue ✓
- C. A livelock that resolves once the queues drain; the single-queue variant is nesting `autoreleasepool`
- D. Nothing — `DispatchQueue.sync` is reentrant on serial queues, so both complete
Correct answer: B. Mutual `sync` waits create a cyclic dependency deadlock, and the well-known single-queue form is `sync`-ing onto the very serial queue you're already executing on.
You call `context.perform` correctly for a Core Data background `NSManagedObjectContext`, fetch objects, then pass those `NSManagedObject` instances to the main thread to display. What rule is violated?
- A. None — objects fetched inside `perform` are thread-safe to read anywhere afterward
- B. Managed objects are bound to their context's queue; passing the objects across threads violates the threading contract — pass `NSManagedObjectID` and re-fetch on the main context instead ✓
- C. You must call `context.reset()` before crossing threads, otherwise faults leak
- D. Only saving across threads is unsafe; reading properties of a managed object from any thread is allowed
Correct answer: B. Managed objects are not thread-safe and belong to their context's queue; the safe hand-off is the `objectID`, re-fetched (or `object(with:)`) on the destination context.
In Swift, why can capturing 'self' strongly in a closure stored by an object cause a retain cycle, and how is it resolved?
- A. Closures cannot capture self; use a global
- B. The object retains the closure and the closure retains self; resolve with [weak self] ✓
- C. self is always weak; no fix needed
- D. Use a struct instead of any closure
Correct answer: B. A stored closure capturing self strongly creates a mutual retain; a [weak self] capture list breaks the cycle.
What is the key behavior of copy-on-write for a Swift array?
- A. Arrays are reference types with no copying
- B. Arrays behave as values but defer the actual copy until a mutation occurs on a shared buffer ✓
- C. Arrays always copy immediately on assignment
- D. Copy-on-write only applies to classes
Correct answer: B. Swift arrays are value types but use copy-on-write, physically copying the backing buffer only when a shared instance is mutated.
When using async/await with an actor, what does actor isolation guarantee?
- A. Code runs on the main thread only
- B. Mutable state is accessed serially, preventing data races on that actor's state ✓
- C. All methods become synchronous
- D. The actor cannot be captured in closures
Correct answer: B. Actors serialize access to their mutable state, preventing concurrent data races without manual locks.
Why can calling DispatchQueue.main.sync from the main thread cause a deadlock?
- A. The main queue is concurrent
- B. The current work waits for the queued block, but the serial main queue can't run it until the current work finishes ✓
- C. sync always deadlocks on any queue
- D. The block runs on a background thread
Correct answer: B. The main queue is serial; calling sync from it blocks waiting for a block that can't start until the caller returns, deadlocking.
In UIKit, what is the difference between a view's 'frame' and 'bounds' after a rotation transform is applied?
- A. They are always identical
- B. bounds stays in the view's own coordinate space; frame becomes the smallest axis-aligned rectangle enclosing the transformed view ✓
- C. frame is unaffected by transforms
- D. bounds includes the superview origin
Correct answer: B. bounds is in the view's local coordinate system, while frame after a transform is the enclosing axis-aligned rect in the superview.
What problem does the @MainActor attribute solve in Swift concurrency?
- A. It parallelizes UI code
- B. It guarantees the annotated code runs on the main actor/thread, safely serializing UI updates ✓
- C. It disables the main thread
- D. It converts async code to sync
Correct answer: B. @MainActor ensures the code hops to and runs on the main actor, making UI updates thread-safe by construction.
In Core Data with multiple contexts, what is the recommended pattern for background work?
- A. Share one context across all threads
- B. Use a private-queue context and perform work inside performBackgroundTask / perform blocks, then merge ✓
- C. Access managed objects directly from any thread
- D. Disable the persistent store coordinator
Correct answer: B. Managed objects/contexts are not thread-safe; use per-queue contexts and their perform blocks, merging changes to the main context.
Why does an implicitly unwrapped optional (Type!) trade safety for convenience?
- A. It cannot be nil ever
- B. It behaves like a normal optional but crashes on access if still nil, so it assumes the value is set before first use ✓
- C. It makes the property lazy
- D. It converts to a computed property
Correct answer: B. An implicitly unwrapped optional auto-unwraps on access and crashes if nil, trading compile-time safety for terser syntax.
When bridging Objective-C to Swift, why might a method used as a #selector target need the @objc attribute?
- A. Swift methods are all Objective-C compatible by default
- B. The Objective-C runtime needs the method exposed via @objc for selector-based dynamic dispatch ✓
- C. @objc makes the method faster
- D. Selectors only work with structs
Correct answer: B. Selector-based APIs use the Objective-C runtime, which requires the method to be exposed with @objc to be found dynamically.
Why can a Task { } created in a SwiftUI button action inadvertently outlive the view, and how do you tie it to the view lifecycle?
- A. Tasks are always cancelled with the view
- B. An unstructured Task is independent; use the .task modifier or store/cancel it so it cancels when the view disappears ✓
- C. Tasks cannot be created in views
- D. Use DispatchQueue instead
Correct answer: B. An unstructured Task runs independently of the view; the .task modifier binds a task to the view's lifecycle and cancels it on disappear.
In Swift's ARC, an object A holds a strong ref to B, and B needs to reference A without keeping it alive. Which is the safest choice when B's reference may become nil?
- A. unowned reference
- B. weak reference ✓
- C. strong reference
- D. implicitly unwrapped strong
Correct answer: B. A weak reference becomes nil safely when the target deallocates, whereas unowned crashes on access after dealloc.
You see a data race on a shared mutable dictionary accessed from multiple queues. Using a serial dispatch queue with a concurrent read barrier, which pattern is correct?
- A. Sync reads, sync writes
- B. Concurrent queue: sync reads, async barrier writes ✓
- C. All async no barrier
- D. Global queue with no sync
Correct answer: B. The reader-writer pattern uses concurrent sync reads and async barrier writes for safe, performant access.
In SwiftUI, a List scrolls poorly because each row recomputes expensive derived data on every diff. What is the best remedy?
- A. Add more @State to the row
- B. Precompute/memoize data in the model and give rows stable Identifiable IDs ✓
- C. Wrap each row in a GeometryReader
- D. Force full-view redraws
Correct answer: B. Stable identity plus precomputed model data lets SwiftUI diff minimally and skip redundant recomputation.
An app is terminated by the OS with a memory jetsam event. Which tool/technique best identifies the abstract retained-memory growth?
- A. Time Profiler for CPU
- B. Instruments Allocations/Leaks and the memory graph debugger ✓
- C. Network Link Conditioner
- D. Console print statements only
Correct answer: B. Allocations/Leaks instruments and the memory graph debugger reveal retained objects and cycles causing growth.
Using Swift async/await, you launch several independent network fetches that should run in parallel and all complete. Which construct is idiomatic?
- A. A sequential for-await loop
- B. async let bindings or a TaskGroup ✓
- C. DispatchGroup with completion handlers
- D. Nested completion closures
Correct answer: B. `async let` or a TaskGroup starts child tasks concurrently and awaits their combined results structurally.
In Core Data with a background context saving while the main context reads, you must merge changes safely. What is the correct setup?
- A. Share one context across threads
- B. Use parent/child contexts or automaticallyMergesChangesFromParent with proper context confinement ✓
- C. Disable the persistent store
- D. Save only on the main thread
Correct answer: B. Contexts are thread-confined; a parent/child or merge-notification setup safely propagates saved changes.
A value-type struct with a large array is copied frequently, hurting performance. Which Swift feature mitigates this cost automatically?
- A. Manual reference counting
- B. Copy-on-write (COW) used by standard library collections ✓
- C. Marking the struct final
- D. Boxing into NSObject
Correct answer: B. Standard collections use copy-on-write, deferring the actual copy until a mutation occurs on a shared buffer.
You must ensure a Swift actor's method that awaits inside does not assume state is unchanged after the suspension point. This hazard is called:
- A. Priority inversion
- B. Actor reentrancy ✓
- C. Deadlock
- D. Retain cycle
Correct answer: B. Actors are reentrant, so other calls can mutate state during an await; code must re-validate assumptions afterward.
For a smooth 120Hz ProMotion animation, which is the most important consideration versus a 60Hz baseline?
- A. Halving image resolution
- B. Keeping per-frame work well under the shorter frame budget (~8.3ms) ✓
- C. Disabling Core Animation
- D. Rendering on the main thread only
Correct answer: B. At 120Hz each frame budget shrinks to ~8.3ms, so per-frame work must fit that tighter window to avoid drops.
You need to persist a small amount of sensitive data like an auth token securely on device. Which storage is appropriate?
- A. UserDefaults
- B. Keychain Services ✓
- C. A plist in Documents
- D. In-memory only
Correct answer: B. The Keychain provides encrypted, access-controlled storage suited for secrets, unlike plain UserDefaults.