swiftui - NavigationLink 在 NavigationStack 中触发多次

标签 swiftui swiftui-navigationlink swiftui-navigationstack

NavTestChildView 多次调用时,我遇到了这个问题。我不明白出了什么问题。我在装有 iOS 16.0.3 和模拟器 Xcode 14.0.1 的真实设备上进行了测试

我替换了原始代码以提供更多关于我将 NavTestService 创建到 navigationDestination 的架构的信息。

enum NavTestRoute: Hashable {
    case child(Int)
}

class NavTestService: ObservableObject {
    let num: Int
    
    init(num: Int) {
        self.num = num
        print("[init][NavTestService]")
    }

    deinit {
        print("[deinit][NavTestService]")
    }
}

struct NavTestChildView: View {
    @EnvironmentObject var service: NavTestService

    init() {
        print("[init][NavTestChildView]")
    }

    var body: some View {
        Text("NavTestChildView \(service.num)")
    }
}

struct NavTestMainView2: View {
    var body: some View {
        VStack {
            ForEach(1..<10, id: \.self) { num in
                NavigationLink(value: NavTestRoute.child(num)) {
                    Text("Open child \(num)")
                }
            }
        }
    }
}

struct NavTestMainView: View {
    var body: some View {
        NavigationStack {
            NavTestMainView2()
                .navigationDestination(for: NavTestRoute.self) { route in
                    switch route {
                    case let .child(num):
                        NavTestChildView().environmentObject(NavTestService(num: num))
                    }
                }
        }
    }
}

日志:

[init][NavTestChildView]
[init][NavTestService]
[deinit][NavTestService]
[init][NavTestChildView]
[init][NavTestService]

最佳答案

看起来有一段时间 NavTestService 的实例没有被任何人持有并且它离开了堆。实际上,这几乎不会发生,因为 .environmentObject 变量通常位于层次结构的某个位置。 如果相应地更改 NavTestMainView:

struct NavTestMainView: View {
    let navTestService = NavTestService()
    var body: some View {
        NavigationStack {
            NavigationLink(value: NavTestRoute.child) {
                Text("Open child")
            }
            .navigationDestination(for: NavTestRoute.self) { route in
                switch route {
                case .child:
                    NavTestChildView().environmentObject(navTestService)
                }
            }
        }
    }
}

...您没有deinit,也没有额外的init。控制台会输出:

[init()][NavTestService]
[init()][NavTestChildView]
[init()][NavTestChildView]

另请注意,如果您注释掉 let navTestService = NavTestService() 并将 NavTestChildView().environmentObject(NavTestService()) 包裹在 LazyView 中,您将获得以下内容输出:

[init()][NavTestChildView]
[init()][NavTestService]

LazyView 是:

struct LazyView<Content: View>: View {
    let build: () -> Content
    init(_ build: @autoclosure @escaping () -> Content) {
        self.build = build
    }
    var body: Content {
        build()
    }
}

关于swiftui - NavigationLink 在 NavigationStack 中触发多次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74056543/

相关文章:

swift - 懒惰不行!无法在属性初始值设定项中使用实例成员 'field';属性初始值设定项在 'self' 可用之前运行

listview - SwiftUI - NavigationLink 的目的地创建具有额外空间的 View

ios - 为什么清空 NavigationStack 路径后对象仍在内存中?

ios - SwiftUI NavigationLink isActive 绑定(bind)未更新/工作

ios - 在 iOS 10+ 项目中导入具有 13.0 目标的社区 SwiftUI 包

swift - SwiftUI 中 NavigationView 导航栏的自定义后退按钮

xcode - undefined symbol ___llvm_profile_runtime

swift - 如果列表顺序更改,SwiftUI NavigationView 中的选择会丢失

swiftui - 从 SwiftUI 中的导航堆栈中删除屏幕