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

SwiftUI中StateObject被两次初始化,如何保证仅初始化一次?

问题根因

你遇到的ProjectViewModel初始化多次的问题是由两个错误用法共同导致的:

  • SwiftUI的View是值类型,每当视图树状态变化需要重新计算布局时,都会重新生成ProjectView结构体实例,对应的初始化方法会被多次调用。
  • 你在自定义init中主动执行了ProjectViewModel的构造闭包,同时提前访问了未被托管的@StateObject的wrappedValue,导致每次ProjectView初始化时都会生成新的ProjectViewModel实例,哪怕@StateObject本身最终只会保留第一个实例,多余的实例也会被创建出来。
  • StateObject的初始化方法接收的是@autoclosure类型的参数,本意是延迟到视图第一次加载时才执行构造逻辑,你提前调用构造闭包的写法绕过了这个延迟机制。

修复方案

推荐调整逻辑,将子ViewModel放到主ViewModel中管理,同时修正@StateObject的初始化写法:

第一步:修改ProjectViewModel,内置子ViewModel

class ProjectViewModel: ObservableObject {
    // 原有属性保留
    @Published var tonalityViewModel: TonalityViewModel!
    @Published var tempoViewModel: TempoViewModel!
    
    init(recording: RecordingFile) {
        // 原有初始化逻辑保留
        tonalityViewModel = createTonalityViewModel()
        tempoViewModel = createTempoViewModel()
    }
    
    init(filePath: String?) {
        // 原有初始化逻辑保留
        tonalityViewModel = createTonalityViewModel()
        tempoViewModel = createTempoViewModel()
    }
    
    // 原有createTonalityViewModel、createTempoViewModel方法保留
}

第二步:修改ProjectView的初始化逻辑

struct ProjectView: View {
    @StateObject private var viewModel: ProjectViewModel

    private init(viewModel: @autoclosure @escaping () -> ProjectViewModel) {
        // 直接将autoclosure传给StateObject,不提前执行构造
        _viewModel = StateObject(wrappedValue: viewModel())
    }

    init(recording: RecordingFile) {
        self.init(viewModel: ProjectViewModel(recording: recording))
    }

    init(filePath: String?) {
        self.init(viewModel: ProjectViewModel(filePath: filePath))
    }
    
    var body: some View {
        // 需要使用子ViewModel时直接调用viewModel.tonalityViewModel、viewModel.tempoViewModel即可
    }
}

修复后效果

ProjectViewModel的构造闭包只会在ProjectView第一次被加载到视图树时执行一次,后续视图重新计算生成ProjectView实例时不会再触发构造逻辑,完全满足仅初始化一次的要求。

内容的提问来源于stack exchange,提问作者Semyon Tikhonenko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 04:30:02