Swift interviewers listen for compiler literacy
Five engineers spent 2024–2026 writing about the same Swift features — value types, opaque types, actors, [weak self], region-based isolation. None of them wrote to prep you for an interview. Read them side by side and the interview version shows up on its own. Here is the reading list.
Swift is Apple's modern language for iOS, macOS, and server workloads, designed to catch entire bug classes at compile time. Interview rounds test whether you can read the compiler's refusals and name what the feature protects. Reciting feature lists isn't the point.
Jacob Bartlett ran fifty interviews in one month and wrote the survival guide at Jacob's Tech Tavern in February 2026 — CV, recruiter, technical rounds, take-homes, panels. Donny Wals has a running Swift Concurrency archive that reads like the Swift interview prep nobody told you existed — the September 2025 post How to unwrap [weak self] in Swift Concurrency Tasks is the piece to open first. Ole Begemann writes at oleb.net about ownership, type-system internals, and WWDC session recaps — the adjacent material for the cases [weak self] papers over. None of these three writers sat down to prep you for an interview.
Read them together and the interview version shows up anyway.
That is the frame for this whole post. Swift interviews at Apple, Snap, Uber, Lyft, Netflix, and Cash App are rarely probing whether you can recite feature lists. They probe whether you have read the engineers who write publicly about why the compiler refuses the code you want to write. If you came from the iOS coding interview guide, you already know the loop. This post is the reading list that makes the language round survive contact with the follow-up.

“The interview is not asking what Swift does. It is asking which engineer you would quote if the feature broke in production.”
Value vs reference — prefer struct
Default to struct. Reach for class only when you need identity, a reference-counted resource, Objective-C interop, or a real inheritance chain. That's the entire rule. Every interview follow-up bends back to it.
Apple's The Swift Programming Language book puts it in one sentence: "A value type is a type whose value is copied when it's assigned to a variable or constant, or when it's passed to a function." Paul Hudson's Hacking with Swift archive walks through the copy-on-write mechanics: Array, Dictionary, and String do not actually copy storage until you mutate. The compiler proves uniqueness, the copy gets elided, thread safety falls out for free.
The scenario interviewers circle: you pass a [User] into a function, it mutates. What does the caller see? Not "nothing, Swift copies it" — that's the half-answer. The full answer: the compiler proves the array is uniquely referenced, elides the copy at the ABI level, and the caller sees its original contents because value semantics are the contract, not the implementation.
struct
class
Reach for when
Data, geometry, tokens, models
Identity, resources, Obj-C interop
Storage
Stack, copied
Heap, shared
Threading
Safe by default
Needs locks or actors
Identity
Value equality
=== reference identity
Memory cost
No ARC
ARC on every copy
The "reach for when" row is the one the interview actually grades. FileHandle, URLSession, CALayer — Apple's own libraries — all classes because they're wrapping OS resources with identity. Your User model is not that.
some vs any — prefer some
Use some Protocol unless you actually need a heterogeneous collection. That's the whole interview answer. The compiler picks one concrete type for some; any boxes it on the heap with a witness table and dispatches dynamically. Performance-free abstraction vs runtime polymorphism.
Protocols carry default implementations via extensions, types can retroactively conform, and conditional conformance lets you write Array: Equatable where Element: Equatable. That last one is the cleverness the interview probes. John Sundell at Swift by Sundell has written repeatedly about opaque and existential types — the reader email on this one never slows down.
// opaque — one concrete type the compiler picks, caller never learns which
func makeHeader() -> some View {
HStack {
Image(systemName: "swift")
Text("Compiler-enforced identity")
}
}
// existential — heterogeneous collection, witness-table dispatch
var views: [any View] = [Text("a"), Image(systemName: "b")]SwiftUI's entire body: some View convention exists because the returned composed type is specific and static — the compiler specializes the whole view hierarchy. Swift 5.7 (SE-0346) added primary associated types, which is how you get any Collection<Int> — the existential form that finally carries its element type. Before 5.7, this was the senior-level stall: why can't you write let stacks: [Stack<Int>] = []? Because generic protocols were not types. After 5.7, the answer is: now they can be, with the primary-associated-type syntax.
some (opaque)
any (existential)
Reach for when
Hiding impl, keeping speed
Heterogeneous collections
Boxing
None
Heap box + witness table
Dispatch
Static, inlinable
Dynamic via witness table
At call site
One concrete type
Any conforming type
For the history: SE-0244 is the proposal that introduced opaque return types in Swift 5.1, and Sundell's archive at swiftbysundell.com is where the teaching-form explainers live. Cite both when the follow-up demands it.
Concurrency — the part Wals wrote a whole book about
Actor isolation is how actors protect their mutable state. SE-0306 says so directly: "the primary mechanism for this protection is by only allowing their stored instance properties to be accessed directly on self." One sentence, the whole feature.
Donny Wals' Swift Concurrency archive is basically the interview prep nobody told you existed. Two things to understand before any loop:
- async/await desugars into continuations on a cooperative thread pool. The word cooperative is the one the interviewer wants. Cite the term and SE-0304 and you have answered half the question.
- actors are reference types the compiler wraps in a serial executor. Two concurrent tasks cannot run actor-isolated code at the same time. No locks, no condition variables, just message serialization.
Sendableis the proof that a type is safe to cross actor boundaries —struct Foo { let x: Int }is Sendable automatically,class Baris not until you annotate it.
actor BankAccount {
let accountNumber: Int
var balance: Double
func transfer(amount: Double, to other: BankAccount) {
balance -= amount
other.balance += amount
// compile error: actor-isolated property 'balance' can not be mutated on a different actor instance
}
}That compile error is the whole interview. The logic reads correct. The compiler refuses. Cross-actor property access is illegal — you have to await other.deposit(amount) and let the target actor serialize the mutation. Candidates who walk through why the compiler blocked them get offers. Candidates who patch the logic without naming the refusal do not.
Swift 6 (2024) ships region-based isolation (SE-0414) and the sending keyword (SE-0430) — ways to hand a non-Sendable value across an actor boundary when the compiler can prove only one reference exists at the handoff. Ole Begemann's ownership writeup on SE-0377 covers the adjacent modifiers (borrowing, consuming). Most interviews have not caught up to any of this yet. Knowing it is how you signal that you read ahead of the loop.
Memory, ARC, and the [weak self] question Jacob Bartlett keeps seeing
ARC — Automatic Reference Counting — inserts retain and release calls at assignment, function call, and return boundaries. The compiler does the bookkeeping; you pay the cost. Strong, weak, and unowned control what happens inside closures and data structures.
The capture-list question is the one every senior iOS loop circles back to. The easy version: does self get captured strongly in a closure? Yes, you add [weak self], done. The hard version: where does [weak self] make things worse?
That is where Donny Wals' How to unwrap [weak self] in Swift Concurrency Tasks earns its keep. He walks through the case where [weak self] silently drops a completion handler because self deallocated mid-flight. The Alamofire source on GitHub carries a cluster of comments in its closure helpers about this exact pattern — they prefer [unowned self] inside the request pipeline because the lifetime is proven by the state machine, and the whole point is to not no-op the callback when self dies.
class ViewModel {
var onLoad: (() -> Void)?
func attach() {
onLoad = { [weak self] in
guard let self else { return } // silent drop if self is gone
self.render()
}
}
}The closure retains the view model; the view model retains the closure; that is the strong cycle. [weak self] breaks it. [unowned self] breaks it too, but crashes if self deallocates before the closure fires — which is why production code almost always picks weak unless a state machine proves the lifetime.
Ownership features (SE-0377, Swift 5.9+) add consuming and borrowing as explicit copy-suppression vocabulary. consuming means the function takes ownership. borrowing means it only reads. Useful when copies are expensive — noncopyable types, big buffers, move-only semantics. Expect the staff follow-up there if the role is server-side Swift or embedded.
Go deeper — the reading list this post is aggregating
If you are walking into a Swift loop in the next month, read these in this order:
- Jacob Bartlett, Interview Grind — 50 interviews in one month, CV through panels. The best public pacing guide for an iOS interview season.
- Donny Wals, Swift Concurrency archive — the running deep-dive. Start with How to unwrap
[weak self]in Swift Concurrency Tasks (Sep 2025) and walk backward through the actor andSendableposts. - John Sundell, Swift by Sundell — archive covering opaque types, existentials, generics, SwiftUI internals. The site's search is the fastest path to the
somevsanyteaching piece. - Paul Hudson, Hacking with Swift — Hudson's free archive for value-type and copy-on-write mechanics from the engineer who wrote the most-read Swift teaching book.
- Apple, SE-0306 Actors and SE-0414 Region-based Isolation — the proposals, not the summaries. Read them twice. The interview follow-up that kills candidates is the one that comes from the proposal's Motivation section, not the summary.
- Alamofire's Request.swift — production capture-list patterns. This is what
[weak self]looks like when a state machine is actually doing the lifetime reasoning.
Before your next iOS coding round, open four of these in browser tabs and skim them in sequence. Apple's book is the reference; the rest are the engineers who turn the reference into production reasoning you can cite under pressure. That is the cheat code for this round — not a mnemonic, a reading list.
The iOS coding interview guide is the loop that wraps this language round. The Android coding interview guide is the parallel post for the other mobile stack. Kotlin's nullability and coroutines are the same species of compiler-proof features in a different language — a Kotlin language guide is next in the mobile track.
Fin and Coco are StrongYes editorial personas from the Council of Ternary Vertices — a trinary-star animal civilization that studies Earth's coding-interview process. Anecdotes map animal-universe experience to human interview mechanics; they are NEVER human-career claims. External citations link to public primary sources.
Grounded in public primary sources — Jacob Bartlett (Jacob's Tech Tavern), Donny Wals, Ole Begemann, Paul Hudson (Hacking with Swift), John Sundell (Swift by Sundell), Apple's Swift Programming Language book at docs.swift.org, the Swift Evolution proposals (SE-0302, SE-0304, SE-0306, SE-0377, SE-0414, SE-0430), and Alamofire's public source. No login-walled citations.
Last verified Apr 17, 2026.
Practice Swift.
Reading builds recognition. Explaining builds recall. Run these problems with Fin or Coco.