NavigationStack的.navigationDestination块在页面推送时为何执行两次?
原因
这种现象是SwiftUI视图更新机制的正常表现,核心原因有两点:
- 当
NavigationPath状态变化时,NavigationStack会重新计算内部视图树,navigationDestination的闭包作为视图构建逻辑的一部分,会被SwiftUI多次调用以确认视图内容——这并不代表视图被重复渲染,只是初始化代码被执行了多次。 NavigationPathHolder作为ObservableObject,其@Published属性navigationPath更新时,会触发依赖它的ContentView重新计算body,间接导致navigationDestination闭包被执行多次。
需要注意:SwiftUI会负责管理视图的实际渲染,即使闭包执行多次,界面上只会显示一个SecondView实例,但如果初始化代码带有副作用(比如网络请求、状态修改),就会引发非预期行为。
解决办法
针对这个问题,可通过以下方式处理:
1. 移除闭包内的副作用代码
不要在navigationDestination闭包中执行有副作用的操作(比如示例中的print),这类逻辑应该放到视图的onAppear生命周期方法或视图内部:
.navigationDestination(for: Int.self) { number in SecondView(number: number) .onAppear { print("Called \(number)") } }
2. 确保视图初始化无副作用
如果SecondView的初始化有必须执行的逻辑,将其移到视图的init方法中,并确保重复执行不会产生问题,或使用lazy属性延迟初始化资源:
struct SecondView: View { @EnvironmentObject var navigationPathHolder: NavigationPathHolder let number: Int init(number: Int) { self.number = number // 确保此处逻辑重复执行无不良影响 print("SecondView initialized with \(number)") } var body: some View { Text("\(number)") } }
3. 稳定视图标识(可选)
如果视图初始化逻辑非常重,可给SecondView添加id,让SwiftUI识别为同一个实例:
.navigationDestination(for: Int.self) { number in SecondView(number: number) .id(number) }
内容的提问来源于stack exchange,提问作者Mac
相关产品推荐
相关产品推荐

