iOS & SwiftUI Interview Questions
SwiftUI interviews tend to probe three layers at once: whether you understand SwiftUI's declarative rendering model, whether you can reason about state ownership and data flow, and whether you know the surrounding iOS ecosystem — concurrency, persistence, and testing. This topic collects representative questions spanning those layers, phrased the way they typically come up in a technical screen, along with concise, technically accurate answers you can use to check your own understanding rather than memorize verbatim.
Cricket analogy: Like a cricket selector's interview that probes technique, temperament, and match awareness all at once rather than just batting average, a SwiftUI interview probes rendering, state ownership, and ecosystem knowledge together.
State and data flow questions
'What's the difference between @State and @Binding?' — @State is a source of truth owned by a view; SwiftUI stores its value outside the view's struct so it survives re-renders, and mutating it invalidates the view. @Binding is a reference to state owned elsewhere, letting a child view read and write a parent's @State without owning it itself. 'When would you use @Observable versus @StateObject/@ObservedObject?' — @Observable (Swift's Observation framework, iOS 17+) is the modern default for reference-type models; it tracks only the specific properties a view reads, avoiding the whole-object invalidation that ObservableObject with @Published incurs, and you no longer need @Published or @ObservedObject wrappers on properties or references. Codebases still targeting earlier iOS versions or third-party dependencies use the older ObservableObject-based system.
Cricket analogy: Like the difference between a team's official scorecard (owned by the scorer, @State) and a commentator's live feed referencing it (@Binding), @Observable in iOS 17+ only updates the broadcast when the specific stat you're watching actually changes.
// Common interview prompt: "Why does this view over-render, and how would you fix it?"
@Observable
final class CartModel {
var items: [Item] = []
var promoCode: String = ""
}
struct CartBadge: View {
let model: CartModel
var body: some View {
// Only reads `items.count`, so this view re-renders
// only when items changes -- NOT when promoCode changes.
Text("\(model.items.count)")
}
}Concurrency and lifecycle questions
'How does .task differ from .onAppear plus a manually launched Task?' — .task attaches an async operation to a view's lifetime: it starts when the view appears and, importantly, is automatically cancelled when the view disappears, which onAppear plus a manually created Task does not give you for free. 'What does @MainActor do, and where does SwiftUI apply it implicitly?' — @MainActor constrains code to run on the main thread; SwiftUI view bodies and property wrappers like @State are implicitly main-actor-isolated, which is why updating UI-bound state from a background context requires hopping back with await MainActor.run or by marking the containing type/function @MainActor. 'What's structured concurrency, and why does it matter here?' — child tasks are scoped to their parent's lifetime (e.g., via async let or a task group), so cancellation and error propagation flow automatically, unlike detached, unstructured Tasks that must be tracked and cancelled manually.
Cricket analogy: Like a rain-delay resumption rule that automatically cancels a bowler's over if play is called off, .task cancels its async work automatically when a view disappears, unlike onAppear plus a manually launched Task that keeps running unattended.
Architecture and testing questions
'Why use MVVM in a SwiftUI app when SwiftUI views are already somewhat like view models?' — a ViewModel isolates business logic and networking/persistence side effects from the view, which makes that logic unit-testable without instantiating SwiftUI's rendering pipeline, and it gives you a seam for dependency injection (e.g., injecting a protocol-typed service instead of a concrete URLSession-backed one). 'How would you unit test a ViewModel that fetches data asynchronously?' — inject a protocol abstraction over the network/service layer, provide a mock/stub conforming to it in tests, call the ViewModel's async method with await, and assert on its published/observable state afterward — no XCTest UI hosting required. 'What's the purpose of Previews versus UI tests?' — previews give fast, in-editor visual feedback for a given state without running the full app or a simulator boot, while UI tests (XCUITest) drive the actual running app to verify end-to-end behavior and are slower but catch integration issues previews can't.
Cricket analogy: Like a team analyst's stats module that can be tested independently of match day by feeding it recorded data (mock AuthServicing), a ViewModel isolates business logic so canSubmit-style rules are testable without running the full broadcast pipeline (SwiftUI rendering).
A strong interview answer usually names the trade-off, not just the mechanism — e.g., '@Observable is more granular than ObservableObject because it tracks per-property access, which reduces unnecessary re-renders' shows you understand why, not just what.
A frequent trap: candidates describe @State as 'just a property wrapper for local variables' without mentioning that SwiftUI actually persists the value in its own storage across view re-creations — that distinction is exactly what interviewers are checking for when they ask 'where does @State live?'
Performance and debugging questions
'How would you diagnose a SwiftUI view that re-renders too often?' — use Instruments' SwiftUI template to see body re-invocation counts, check whether an @Observable model is being read more broadly than needed (e.g., passing the whole model instead of narrower bindings), and check List/ForEach identity — unstable id values force full diffs instead of minimal updates. 'Why is List identity (Identifiable / id:) important for performance?' — SwiftUI diffs collections by identity, not index; stable, unique ids let it reuse existing row views and animate insertions/removals correctly, while identity collisions or using array index as id can cause incorrect reuse and visual glitches when the array changes.
Cricket analogy: Like a coach reviewing a full match replay (Instruments) to spot a fielder repositioning unnecessarily on every ball, unstable List ids force SwiftUI to redo a full diff instead of reusing existing rows, causing wasted re-renders.
- Be ready to explain @State vs @Binding and @Observable vs ObservableObject with the reasoning behind each, not just the syntax.
- .task's automatic cancellation on view disappearance is a common concurrency talking point.
- @MainActor and structured concurrency (async let, task groups) are frequent follow-up topics after basic async/await questions.
- MVVM's value in interviews is framed around testability and dependency injection, not a hard SwiftUI requirement.
- Explain the difference between Previews (fast, in-editor) and XCUITest UI tests (slower, full end-to-end).
- Name concrete tools (Instruments' SwiftUI template) when asked how you'd diagnose performance issues.
Practice what you learned
1. In an interview, how should you best explain where @State's value actually lives?
2. What is the key advantage of @Observable over the older ObservableObject/@Published pattern?
3. Why does .task offer an advantage over .onAppear combined with a manually created Task for async work?
4. What is the primary architectural reason for introducing a ViewModel layer in a SwiftUI app?
5. Why can using an array's index as a List row's id cause bugs when the array is mutated?
Was this page helpful?
You May Also Like
@State and @Binding
Understand how @State owns local view state and how @Binding lets child views read and write that state without owning it themselves.
The @Observable Macro
See how the iOS 17 @Observable macro replaces ObservableObject with automatic, fine-grained property tracking that simplifies SwiftUI model code.
MVVM in SwiftUI
Understand how the Model-View-ViewModel pattern maps onto SwiftUI's declarative views, when it earns its complexity, and how it differs from plain @State-driven views.
Common iOS & SwiftUI Pitfalls
Frequent mistakes SwiftUI developers make around state ownership, list identity, concurrency, and view identity, with clear explanations of why they break.