最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - SwiftUI NavigationPath in NavigationStack(path: $path) in NavigationSplitView does not Compile - Stack Overflow

programmeradmin2浏览0评论

I have a simple NavigationSplitView app with a simple SwiftData model. I'm trying to use NavigationPath in order to return to the ThingListView when several layers deep. Every article I've found and three different AI coders say this code should work, but it does not compile. In the detail: below, the line "NavigationStack(path: $router.path) {" raises the error "Cannot find '$router' in scope".

import SwiftUI
import SwiftData
import Observation

@main
struct ThingNavigationPathApp: App {
    
    @State private var router = Router()
    
    var body: some Scene {
        WindowGroup {
            ThingListView()
                //.environment(router)
        }
        .modelContainer(for: [Thing.self])
        .environment(router)
    }
}

@Observable
class Router {
    var path = NavigationPath()
        
    func navigateToRoot() {
        path = NavigationPath()
    }
}

struct ThingListView: View {
    
    @Environment(\.modelContext) private var context
    @Query(sort: \Thing.name) private var things: [Thing]
    @Environment(Router.self) private var router
    
    @State private var selectedThing: Thing?
    @State private var searchText = ""
    
    var body: some View {
        NavigationSplitView {
            VStack {
                Text("Things")
                
                List(selection: $selectedThing) {
                    ForEach(things, id: \.self) { thing in
                        NavigationLink(value: thing) {
                            ThingRowView(thing: thing)
                        }
                    }
                }
                .searchable(text: $searchText)
                
                Button(action: {
                    Task {
                        //do some setup
                    }
                }, label: {
                    Text("Load Examples")
                })
            }
        } detail: {
            NavigationStack(path: $router.path) {
                VStack {
                    if let selectedThing = selectedThing {
                        ThingDetailView(selectedThing: selectedThing)
                    } else {
                        PlaceholderView()
                    }
                }
                .navigationDestination(for: Thing.self) { thing in
                    ThingEditView(thing: thing)
                }
            }//nav
        }
    }
}

And just for completeness:

@Model
final public class Thing {
    
    var name: String = ""
    var comment: String = ""
    var imageData: Data?
    var count: Int = 0
    
    init(name: String, comment: String, imageData: Data? = nil, count: Int) {
        self.name = name
        selfment = comment
        self.imageData = imageData
        self.count = count
    }

    static let one = Thing(name: "Thing One", comment: "fruit", count: 1)
    static let two = Thing(name: "Thing Two", comment: "vegetable", count: 2 )
    static let three = Thing(name: "Thing Three", comment: "protein", count: 3)
    
}//class thing

struct ThingDetailView: View {
    @Environment(\.modelContext) private var context
    @Environment(Router.self) private var router
    
    
    let selectedThing: Thing

    @State private var newUIImage: UIImage? = nil
    @State private var disableSaveButton: Bool = false
    @State private var shouldEditPhoto: Bool = false
    
    var body: some View {
            List {
                Section {
                    NavigationLink(value: selectedThing) {
                        ThingRowView(thing: selectedThing)
                    }
                } header: {
                    Text("Thing Name")
                }
            }
            .navigationTitle(selectedThing.name)
    }
}

Any guidance would be appreciated. Xcode 16.2, iOS 18.2

I have a simple NavigationSplitView app with a simple SwiftData model. I'm trying to use NavigationPath in order to return to the ThingListView when several layers deep. Every article I've found and three different AI coders say this code should work, but it does not compile. In the detail: below, the line "NavigationStack(path: $router.path) {" raises the error "Cannot find '$router' in scope".

import SwiftUI
import SwiftData
import Observation

@main
struct ThingNavigationPathApp: App {
    
    @State private var router = Router()
    
    var body: some Scene {
        WindowGroup {
            ThingListView()
                //.environment(router)
        }
        .modelContainer(for: [Thing.self])
        .environment(router)
    }
}

@Observable
class Router {
    var path = NavigationPath()
        
    func navigateToRoot() {
        path = NavigationPath()
    }
}

struct ThingListView: View {
    
    @Environment(\.modelContext) private var context
    @Query(sort: \Thing.name) private var things: [Thing]
    @Environment(Router.self) private var router
    
    @State private var selectedThing: Thing?
    @State private var searchText = ""
    
    var body: some View {
        NavigationSplitView {
            VStack {
                Text("Things")
                
                List(selection: $selectedThing) {
                    ForEach(things, id: \.self) { thing in
                        NavigationLink(value: thing) {
                            ThingRowView(thing: thing)
                        }
                    }
                }
                .searchable(text: $searchText)
                
                Button(action: {
                    Task {
                        //do some setup
                    }
                }, label: {
                    Text("Load Examples")
                })
            }
        } detail: {
            NavigationStack(path: $router.path) {
                VStack {
                    if let selectedThing = selectedThing {
                        ThingDetailView(selectedThing: selectedThing)
                    } else {
                        PlaceholderView()
                    }
                }
                .navigationDestination(for: Thing.self) { thing in
                    ThingEditView(thing: thing)
                }
            }//nav
        }
    }
}

And just for completeness:

@Model
final public class Thing {
    
    var name: String = ""
    var comment: String = ""
    var imageData: Data?
    var count: Int = 0
    
    init(name: String, comment: String, imageData: Data? = nil, count: Int) {
        self.name = name
        selfment = comment
        self.imageData = imageData
        self.count = count
    }

    static let one = Thing(name: "Thing One", comment: "fruit", count: 1)
    static let two = Thing(name: "Thing Two", comment: "vegetable", count: 2 )
    static let three = Thing(name: "Thing Three", comment: "protein", count: 3)
    
}//class thing

struct ThingDetailView: View {
    @Environment(\.modelContext) private var context
    @Environment(Router.self) private var router
    
    
    let selectedThing: Thing

    @State private var newUIImage: UIImage? = nil
    @State private var disableSaveButton: Bool = false
    @State private var shouldEditPhoto: Bool = false
    
    var body: some View {
            List {
                Section {
                    NavigationLink(value: selectedThing) {
                        ThingRowView(thing: selectedThing)
                    }
                } header: {
                    Text("Thing Name")
                }
            }
            .navigationTitle(selectedThing.name)
    }
}

Any guidance would be appreciated. Xcode 16.2, iOS 18.2

Share Improve this question asked Feb 15 at 0:18 JohnSFJohnSF 4,3205 gold badges40 silver badges89 bronze badges 2
  • You can’t nest these 2 navigation types. Also look up the documentation for Bindable, the AIs have huge gaps – lorem ipsum Commented Feb 15 at 1:49
  • Change Router to struct. Can’t use State with class. – malhal Commented Feb 15 at 6:07
Add a comment  | 

2 Answers 2

Reset to default 0

for your code to compile and work, you need to use a @Bindable (aka gives you a Binding for path), as mentioned by @lorem ipsum. Because this is what is expected in the call NavigationStack(path: $router.path).

So simply add this in your ThingListView:

var body: some View {
    @Bindable var router = self.router  // <--- here
    NavigationSplitView {

Can’t use @State with class because it will leak. Change Router to struct, e.g.

struct Router {
    var path = NavigationPath()
        
    mutating func navigateToRoot() {
        path = NavigationPath()
    }
}
发布评论

评论列表(0)

  1. 暂无评论