These are the lesson notes for this day. Its build-along tutorial and flash cards have not been written yet.
.toolbar adds items to the navigation bar, the bottom bar, or the keyboard. Each item has a placement, such as .topBarTrailing or .primaryAction, that describes its role so the system can put it in the right place on each platform. Menu shows a pull-down list of actions. .searchable(text:) adds a search field bound to a string. You filter your own data using that string, and can add suggestions, tokens, and scopes.
New in iOS 27: .visibilityPriority keeps the important items visible when space is tight; ToolbarOverflowMenu collects the rest; the .topBarPinnedTrailing placement pins an item in place; and .toolbarMinimizeBehavior(.onScrollDown) shrinks the bar while the user scrolls.
Add to your list a toolbar with an Add button and a Sort menu, and a search field that filters the rows as you type.
After this lesson you should be able to answer.searchable deliver the search text to your view?“A notification arrives carrying https://quest.example/trips/42/log. Write the navigation so that the app opens trip 42 and then its log — and so that a Home button anywhere returns to the root. Then tell me how you would unit test it.”
Where this comes from: Hacking with Swift: iOS interview questions · NavigationStack — from Hacking with Swift's question list: “How would you create programmatic navigation in SwiftUI?”
enum Route: Hashable {
case trip(id: Int)
case log(tripID: Int)
}
@MainActor @Observable
final class Router {
var path: [Route] = []
func open(_ url: URL) { // https://quest.example/trips/42/log
let parts = url.pathComponents.filter { $0 != "/" }
guard parts.first == "trips", parts.count >= 2, let id = Int(parts[1]) else { return }
path = [.trip(id: id)]
if parts.dropFirst(2).first == "log" { path.append(.log(tripID: id)) }
}
func popToRoot() { path.removeAll() }
}
struct RootView: View {
@State private var router = Router()
var body: some View {
NavigationStack(path: $router.path) {
TripList()
.navigationDestination(for: Route.self) { route in
switch route {
case .trip(let id): TripDetail(id: id)
case .log(let tripID): TripLog(tripID: tripID)
}
}
}
.environment(router)
.onOpenURL { router.open($0) }
}
}Navigation is state. The stack on screen is a rendering of router.path. Opening a deep link is assigning an array. Returning to the root is emptying it. Restoring a session is decoding it.
The test comes for free, because the router is plain logic with no view involved: create a Router, call open(url), and assert that path == [.trip(id: 42), .log(tripID: 42)]. Then give it a malformed URL and assert that the path did not change.
What interviewers listen for: Routes that are types rather than strings, one source of truth for the stack, and the observation that turning navigation into data is what made it testable.