Skip to main content
GuideSwiftIosMobile

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.

Fin·Apr 17, 2026·9 min read

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.

Fin the shark in a coral hoodie holding a marker — the DSA coach and squad lead
The interview is not asking what Swift does. It is asking which engineer you would quote if the feature broke in production.
Diagram
Rendering diagram...

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.

SWIFT
// 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. Sendable is the proof that a type is safe to cross actor boundaries — struct Foo { let x: Int } is Sendable automatically, class Bar is not until you annotate it.
SWIFT
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.

SWIFT
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 and Sendable posts.
  • John Sundell, Swift by Sundell — archive covering opaque types, existentials, generics, SwiftUI internals. The site's search is the fastest path to the some vs any teaching 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.

Note

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.

Source note

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.