Design state-driven navigation for a conditional wizard in UIKit and SwiftUI

This tests separating navigation state from UI. Model the flow as a state machine enum, derive the stack from state, and unit test transitions in plain Swift. A red flag is imperative pushes inside views or view controllers.
WHAT THIS TESTS: This question probes your ability to separate navigation concerns from presentation code in a branching user flow. The interviewer wants to see if you treat the wizard sequence as data rather than a series of imperative side effects, and whether you understand how to make that sequence unit testable without launching a UI. They also care that you know the idiomatic iOS patterns for both UIKit and SwiftUI rather than forcing one into the other.
A GOOD ANSWER COVERS: First, model the wizard as a finite state machine using an enum with associated values, where each case represents a screen and carries the data needed for that step. Second, create a single source of truth object such as a WizardRouter or WizardViewModel that owns the current state and computes valid next steps based on user input. Third, for UIKit, use a coordinator pattern where the coordinator owns the UINavigationController and translates state changes into push or pop operations, keeping view controllers dumb and event-only. For SwiftUI, bind a NavigationStack to a collection of those enum cases or a NavigationPath, and mutate that collection from the model so the view is purely declarative. Fourth, ensure all transition logic lives in plain Swift types with no UIKit or SwiftUI imports so you can write fast unit tests that assert the exact stack given a set of user answers.
COMMON WRONG ANSWERS: A major red flag is imperative navigation scattered through view controllers or SwiftUI views, such as calling pushViewController from a button action inside a view controller or using NavigationLink with isActive booleans managed in view state. Another red flag is embedding conditional branching directly into view body code or view controller lifecycle methods, which makes the flow impossible to unit test and prone to drift between platforms. Suggesting you need to wrap a UIKit navigation controller inside SwiftUI to handle complex flows is also a sign of weak SwiftUI knowledge.
LIKELY FOLLOW-UPS: The interviewer may ask how you prevent a user from advancing until validation passes, which you solve by gating the state transition on a validation result. They may ask how you handle going back to edit a previous answer while preserving downstream choices, which you solve by recomputing the tail of the stack from the modified state. They might also ask about supporting deep links or state restoration, serializing the enum array to disk, or how to remotely configure the flow graph without an app update.
ONE CONCRETE EXAMPLE: Imagine a loan application wizard. The user enters personal info, selects loan type, and then either sees income verification for personal loans or business details for commercial loans. In UIKit, a LoanCoordinator holds a UINavigationController and a currentState property; when the user picks commercial, the coordinator transitions state and pushes the business details view controller. In SwiftUI, a LoanViewModel exposes a NavigationPath of LoanRoute values; the root view wraps a NavigationStack around the path binding, and choosing commercial appends LoanRoute.businessDetails to the path. A unit test creates the view model, sends the selectLoanType event, and asserts the path contains exactly personalInfo followed by businessDetails, all without constructing any views.
Read the original → developer.apple.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.