5 exercises — choose the best-structured answer to common Swift Developer interview questions. Focus on precise vocabulary, correct use of technical terms, and demonstrating real experience.
Structure for Swift/iOS interview answers
Name the Swift concurrency primitive: async/await, Task, actor, @MainActor — with the specific problem each solves
Explain actor isolation: describe the serialisation mechanism and the compiler\'s static checking
Address data races: explain how actors prevent races vs manual locking in GCD
Compare with Combine: distinguish one-shot async operations from ongoing value streams
0 / 5 completed
1 / 5
The interviewer asks: "How does Swift's concurrency model with async/await and actors work?" Which answer best explains Swift's modern concurrency system?
Option B is strongest: it explains what async/await replaces (completion handler nesting) and why, introduces Tasks as the unit of work with async let for parallelism, explains actor isolation with the serialisation mechanism (not just "thread safety"), names @MainActor with the specific replacement pattern (DispatchQueue.main.async), explains the compiler's static checking requirement, and compares with Combine across three specific dimensions. Key structure: async/await replaces closure nesting → Task/async let for parallel work → actor serialisation mechanism → @MainActor for UI → compiler static checking → vs Combine comparison. Option C is accurate but does not explain the compiler's static isolation checking or the Combine comparison. Option D mentions structured cancellation (correct) but does not explain actor serialisation or @MainActor.
2 / 5
The interviewer asks: "When would you choose SwiftUI over UIKit, and when would you still use UIKit?" Which answer best demonstrates architectural judgment?
Option B is strongest: it defines declarative vs imperative at the framework level (not just a buzzword), gives specific SwiftUI state management annotations, names three concrete UIKit-only use cases with specifics (Metal, CALayer animations, UICollectionViewCompositionalLayout), explains the bridging API in both directions, and gives the practical heuristic (SwiftUI default, UIKit for abstraction leaks). Key structure: declarative vs imperative model → SwiftUI strengths (state-driven, iOS 16+) → concrete UIKit-only cases → bridging API → practical default rule. Option C mentions live previews and UIViewRepresentable but does not explain declarative vs imperative or give specific UIKit use cases. Option D compares to React/Flutter (valid) but does not name UICollectionViewCompositionalLayout or the iOS version maturity issue.
3 / 5
The interviewer asks: "How do Swift protocols and generics work together, and what is an opaque return type?" Which answer best explains protocol-oriented design?
Option B is strongest: it explains why generics with protocol constraints give static dispatch (zero-cost), covers associated types with a real example (Collection.Element), explains where clauses as a constraint tool, precisely defines opaque return types and the specific problem they solve (associated type in return position), contrasts with existentials (any Protocol, Swift 5.7) at the dispatch level, and gives the concrete SwiftUI example with the reason (compiler optimisation). Key structure: protocol constraints → static dispatch → associated types → where clauses → opaque types solve the PAT-in-return problem → opaque vs existential dispatch difference → SwiftUI body example. Option C is accurate but does not explain the "PAT in return position" problem or the opaque vs existential distinction. Option D mentions the dispatch difference (correct) but does not explain associated types or where clauses.
4 / 5
The interviewer asks: "How does ARC work in Swift, and how do you prevent retain cycles?" Which answer best explains Swift memory management?
Option B is strongest: it explains the compile-time mechanism (compiler inserts retain/release — distinguishing from runtime GC), precisely defines retain cycles with the zero-count blockage reason, gives the specific use case for weak (optional, nil on dealloc, delegates/parent-child) vs unowned (non-optional, assumed alive, tied lifetimes) with concrete examples, explains closure capture lists and why they create cycles, and gives a decision rule between weak and unowned. Key structure: compile-time retain/release → ARC vs GC → retain cycle mechanism → weak (optional, nil, delegates) vs unowned (non-optional, tied lifetimes) → closure capture lists → decision rule. Option C is accurate but recommends "always [weak self] in closures" which ignores valid unowned use cases and does not explain the compile-time mechanism. Option D's "always [weak self] to be safe" is the same antipattern — imprecise and overly cautious.
5 / 5
The interviewer asks: "What is the Combine framework, and when would you use it over async/await?" Which answer best explains the trade-offs?
Option B is strongest: it defines Publisher/Subscriber precisely with the sequence + completion/error contract, lists specific operators with use cases (debounce for input, combineLatest for multi-field validation), explains AnyCancellable lifetime semantics, gives three concrete Combine-preferred scenarios, gives two concrete async/await-preferred scenarios, and ends with a practical decision rule naming frameworks that expose Combine publishers (URLSession, CoreData). Key structure: Publisher/Subscriber with value sequence contract → key operators with use cases → AnyCancellable lifetime → Combine strengths (stream operators, back-pressure) → async/await strengths (one-shot, linear) → practical decision rule + framework examples. Option C names @Published and PassthroughSubject (useful) but does not give the decision rule or explain AnyCancellable lifetime. Option D mentions ObservableObject (correct) but does not explain operator use cases or back-pressure.