You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 06:06:26