未为 .navigationDestination 注入 EnvironmentObject

ero*_*ppa 5 swift swiftui

考虑代码

@EnvironmentObject var navModel: NavigationModel
var body: some View {
    someView
       .navigationDestination(for: ImageModel.self) { imageModel in
                ImageDetailedView(image: imageModel)
                    .environmentObject(navModel)   //this is required 
       }
}
Run Code Online (Sandbox Code Playgroud)

导航不被视为视图的子视图吗?如果是这样,那么在导航堆栈周围不断抛出 environemntObjects 是否正常?

import Combine
import SwiftUI

enum Destination {
    case firstPage
    case secondPage
}

enum Category: Int, Hashable, CaseIterable, Identifiable, Codable {
    case dessert
    case pancake
    case salad
    case sandwich
    
    var id: Int { rawValue }
    
    var localizedName: LocalizedStringKey {
        switch self {
        case .dessert:
            return "Dessert"
        case .pancake:
            return "Pancake"
        case .salad:
            return "Salad"
        case .sandwich:
            return "Sandwich"
        }
    }
}

@available(iOS 16.0, *)
class Coordinator3: ObservableObject {
    @Published var path = NavigationPath()
    
    func gotoHomePage() {
        path.removeLast(path.count)
    }
    
    func tapOnEnter() {
        path.append(Destination.firstPage)
    }
    
    func tapOnFirstPage() {
        path.append(Destination.secondPage)
    }
    
    func tapOnSecondPage() {
        path.removeLast()
    }
    
    func test() {
        path.removeLast(path.count)
        path.append(2)
    }
}

class Test :ObservableObject {
    var name = "test"
}

@available(iOS 16.0, *)
struct SplitTestView: View {
    @State var selectedCategory: Category?
    var categories = Category.allCases
    @ObservedObject var coordinator = Coordinator3()
    @StateObject var test = Test()
    
    var body: some View {
        NavigationSplitView {
            List(categories, selection: $selectedCategory) { category in
                NavigationLink(category.localizedName, value: category)
            }
        } detail: {
            NavigationStack(path: $coordinator.path) {
                switch selectedCategory {
                case .dessert:
                    Text(selectedCategory!.localizedName)
                case .pancake:
                    VStack {
                        Text("Navigation stack")
                            .padding()
                        NavigationLink("NavigationLink to enter first page", value: Destination.firstPage)
                            .padding()
                        NavigationLink("NavigationLink to enter second page", value: Destination.secondPage)
                            .padding()
                    }
                    .navigationDestination(for: Destination.self) { destination in
                        if destination == .firstPage {
                            FirstPage()
                        } else {
                            Text(
                                "SecondPage()"
                            )
                        }
                    }
                case .salad: Text(selectedCategory!.localizedName)
                case .sandwich: Text(selectedCategory!.localizedName)
                case .none: Text("hi")
                }
            }.environmentObject(test)
        }
    }
}

@available(iOS 16.0, *)
struct SplitTestView_Previews: PreviewProvider {
    static var previews: some View {
        SplitTestView()
    }
}
struct FirstPage: View {
    @EnvironmentObject var test: Test
    var body: some View {
        Text("First Page \(test.name)")
    }
}
Run Code Online (Sandbox Code Playgroud)

lor*_*sum 7

这就是为什么 MRE 很重要,这就是为什么我在第一篇评论中提到它,你介绍了NavigationSplitView

场景1

如果您正在使用,NavigationSplitView则必须将 注入EnvironmentObjectNavigationSplitView.

NavigationSplitView{
    /*other stuff that includes a navigationDestination*/
}.environmentObject(navModel)
Run Code Online (Sandbox Code Playgroud)

场景2

当只使用时,NavigationStack您必须注入NavigationStack

NavigationStack{
    /*other stuff that includes a navigationDestination*/
}.environmentObject(navModel)
Run Code Online (Sandbox Code Playgroud)

场景 3 - 已弃用

当只使用时,NavigationView您必须注入NavigationView

NavigationView{
    /*other stuff that includes a NavigationLink*/
}.environmentObject(navModel)
Run Code Online (Sandbox Code Playgroud)

您的样品

只需将注入代码向下移动一行即可。

import Combine
import SwiftUI

@available(iOS 16.0, *)
struct SplitTestView: View {
    @State var selectedCategory: Category?
    var categories = Category.allCases
    @StateObject var coordinator = Coordinator3() //<-- Switch to StateObject
    @StateObject var test = Test()
    
    var body: some View {
        NavigationSplitView {
            List(categories, selection: $selectedCategory) { category in
                NavigationLink(category.localizedName, value: category)
            }
        } detail: {
            NavigationStack(path: $coordinator.path) {
                switch selectedCategory {
                case .dessert:
                    Text(selectedCategory!.localizedName)
                case .pancake:
                    VStack {
                        Text("Navigation stack")
                            .padding()
                        NavigationLink("NavigationLink to enter first page", value: Destination.firstPage)
                            .padding()
                        NavigationLink("NavigationLink to enter second page", value: Destination.secondPage)
                            .padding()
                    }
                    .navigationDestination(for: Destination.self) { destination in
                        if destination == .firstPage {
                            FirstPage()
                        } else {
                            Text(
                                "SecondPage()"
                            )
                        }
                    }
                case .salad: Text(selectedCategory!.localizedName)
                case .sandwich: Text(selectedCategory!.localizedName)
                case .none: Text("hi")
                }
            }
        }.environmentObject(test) //<<--- Add to the NavigationSplitView - The NavigationLink's are presenting in a separate column than the Stack, the only thing they share is the split view.
    }
}
enum Destination {
    case firstPage
    case secondPage
}

enum Category: Int, Hashable, CaseIterable, Identifiable, Codable {
    case dessert
    case pancake
    case salad
    case sandwich
    
    var id: Int { rawValue }
    
    var localizedName: LocalizedStringKey {
        switch self {
        case .dessert:
            return "Dessert"
        case .pancake:
            return "Pancake"
        case .salad:
            return "Salad"
        case .sandwich:
            return "Sandwich"
        }
    }
}

@available(iOS 16.0, *)
class Coordinator3: ObservableObject {
    @Published var path = NavigationPath()
    
    func gotoHomePage() {
        path.removeLast(path.count)
    }
    
    func tapOnEnter() {
        path.append(Destination.firstPage)
    }
    
    func tapOnFirstPage() {
        path.append(Destination.secondPage)
    }
    
    func tapOnSecondPage() {
        path.removeLast()
    }
    
    func test() {
        path.removeLast(path.count)
        path.append(2)
    }
}

class Test :ObservableObject {
    var name = "test"
}



@available(iOS 16.0, *)
struct SplitTestView_Previews: PreviewProvider {
    static var previews: some View {
        SplitTestView()
    }
}
struct FirstPage: View {
    @EnvironmentObject var test: Test
    var body: some View {
        Text("First Page \(test.name)")
    }
}
Run Code Online (Sandbox Code Playgroud)

地址信息

在迁移指南中,苹果讨论了这两种类型之间的差异。

https://developer.apple.com/documentation/swiftui/migration-to-new-navigation-types

他们把里面的东西称为NavigationStack“内容”

NavigationStack {
    /* content */
}
Run Code Online (Sandbox Code Playgroud)

NavigationSplitView还有“柱子”的内部

NavigationSplitView {
    /* column 1 */
} content: {
    /* column 2 */
} detail: {
    /* column 3 */
}
Run Code Online (Sandbox Code Playgroud)

在各自的设置中,“列”和“内容”仅分别与s/共享NavigationSplitView或。NavigationStackNavigationLinknavigationDestination

NavigationLink内部NavigationStack的内部呈现NavigationSplitView在它自己的专栏中。

注入应该始终发生在最上面的共享处View

  • @erotsppa 根据您的链接,即“Apple 的设计”。我看B和C就像是装在纸盒里的鸡蛋一样。A是纸箱。鸡蛋通过纸箱连接。它们不能互相共享,但纸箱可以。我不知道这也许是一个愚蠢的类比。 (2认同)