RSS Feed ↗
VOL. 1 • NO. 14 • IOSBUFFET.COM OCT 25, 2026
Inside Page — A4 Continued from Front
The Daily Recipe
Sep 19, 2026 • Page A4

NavigationStack Deep Links in Forty Lines

A value-driven router turns any URL into a navigation path — no coordinators required.

By M. HOSSAIN — Staff Writer — Sep 19, 2026 570 words

Deep linking used to mean threading flags through half the view hierarchy. With NavigationStack bound to a path, navigation becomes plain data: an array of routes. Parse a URL into that array and the stack rebuilds itself to match.

Start with an enum of every destination the app can push. Making it Hashable is all NavigationStack needs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
enum Route: Hashable {
    case recipe(id: Int)
    case author(name: String)
    case settings
}

@Observable final class Router {
    var path: [Route] = []

    func open(_ url: URL) {
        guard url.scheme == "iosbuffet" else { return }
        let parts = url.pathComponents.dropFirst() // drop "/"
        switch (url.host, parts.first) {
        case ("recipe", let id?):
            if let id = Int(id) { path = [.recipe(id: id)] }
        case ("author", let name?):
            path = [.author(name: name)]
        case ("settings", _):
            path = [.settings]
        default:
            break
        }
    }
}

struct RootView: View {
    @State private var router = Router()

    var body: some View {
        NavigationStack(path: $router.path) {
            HomeView()
                .navigationDestination(for: Route.self) { route in
                    switch route {
                    case .recipe(let id): RecipeView(id: id)
                    case .author(let name): AuthorView(name: name)
                    case .settings: SettingsView()
                    }
                }
        }
        .onOpenURL { router.open($0) }
        .environment(router)
    }
}

Replacing path wholesale means a link always lands in a predictable place, regardless of where the user was. If you’d rather push on top of the current stack, append instead.

Why this scales

Because the path is just an array, it’s trivially testable — feed open(_:) a URL and assert on path without rendering a single view. It’s also Codable if your routes are, which gives you state restoration almost for free.

Universal links follow the same route: handle NSUserActivity with .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) and pass its webpageURL through the same parser.

— 30 —

— END OF EDITION 2026 — SET IN GARAMOND & COURIER ON NEWSPRINT STOCK — iOS BUFFET PRESS — RSS —