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

SwiftUI NavigationStack视图/ViewModel重复创建问题求助

解决SwiftUI NavigationStack中ViewModel多次实例化的问题

问题根源

你当前代码里WelcomeViewModel重复实例化的核心原因是:在RootView的body中直接通过.init()创建实例并传给WelcomeView。SwiftUI会在视图树重绘(比如导航路径变化、状态更新)时重新执行body内的代码,这就导致每次重绘都会生成新的WelcomeViewModel对象。你添加的.id("Welcome")只作用于WelcomeView本身的身份识别,无法阻止参数里的ViewModel被重复初始化。

解决方案

把WelcomeViewModel的实例交由@StateObject管理,@StateObject会确保对象在视图的整个生命周期内只初始化一次,不会因视图重绘而重新创建。

修改后的关键代码

  1. 更新RootView:
struct RootView: View {
    @StateObject var router = Router.shared
    // 用@StateObject持有WelcomeViewModel,保证单实例
    @StateObject private var welcomeVM = WelcomeViewModel(title: "Welcome", router: Router.shared)
    
    var body: some View {
        NavigationStack(path: $router.steps) {
            // 直接传入已初始化的welcomeVM,而非在参数内新建
            WelcomeView(viewModel: welcomeVM)
            .navigationDestination(for: Step.self) { step in
                switch step {
                case .page1:
                    StepView(viewModel: Step1ViewModel(step: step, router: router))
                case .page2:
                    StepView(viewModel: Step2ViewModel(step: step, router: router))
                case .page3:
                    StepView(viewModel: Step3ViewModel(step: step, router: router))
                }
            }
        }
    }
}
  1. 额外优化(可选):
    如果想让Step对应的ViewModel也避免重复创建,可以调整为在StepView内部基于step和router作为标识,结合@StateObject的工厂方法创建:
struct StepView: View {
    let step: Step
    let router: Router
    // 根据step和router生成唯一的ViewModel实例
    @StateObject private var viewModel: BaseStepViewModel {
        switch step {
        case .page1:
            return Step1ViewModel(step: step, router: router)
        case .page2:
            return Step2ViewModel(step: step, router: router)
        case .page3:
            return Step3ViewModel(step: step, router: router)
        }
    }
    
    var body: some View {
        Button {
            viewModel.shopNextPage()
        } label: {
            Text(viewModel.step.rawValue)
        }
    }
}

此时navigationDestination只需传入step和router:

.navigationDestination(for: Step.self) { step in
    StepView(step: step, router: router)
}

效果验证

修改后运行代码,控制台只会打印一次Created welcome view,WelcomeViewModel不会再被重复实例化。

内容的提问来源于stack exchange,提问作者Artem N0t2Day Kedrov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 15:01:00