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

如何从视图模型类中修改模型数据?

如何从视图模型类中修改模型数据?

嘿,我看你现在遇到的问题是在DetailViewModel里修改MyModel的数据,但ContentView里的模型没同步更新对吧?这其实是因为Swift里的struct是值类型,你把model传给DetailViewModel的时候,相当于传了一份副本,修改副本自然不会影响原数据。下面给你两种常用的解决办法:

方法一:把模型改成引用类型(Class)

如果你的模型需要在多个视图或视图模型之间共享状态,把MyModel从struct改成class是最直接的方案。因为类是引用类型,所有持有它的对象操作的都是同一个实例,修改会自动同步。

首先调整MyModel,让它遵循ObservableObject,并用@Published标记需要视图响应的属性:

import SwiftUI

class MyModel: ObservableObject {
    @Published var pages: [Int] = []
}

然后修改ContentView,因为现在是引用类型,要用@StateObject来管理模型实例(@State是给值类型用的):

struct ContentView: View {
    @StateObject private var model = MyModel()
 
    var body: some View {
        NavigationStack {
            VStack {
                Text("Content View")
                // 加个文本显示pages,方便实时查看变化
                Text("Pages count: \(model.pages.count)")
                
                NavigationLink("Details") {
                    DetailView(viewModel: DetailViewModel(model: model))
                }
            }
            .onAppear {
                print(model.pages)
            }
        }
    }
}

接下来是DetailViewModel,直接持有MyModel的引用,修改时操作这个引用即可:

class DetailViewModel: ObservableObject {
    private let model: MyModel
    
    init(model: MyModel) {
        self.model = model
    }
    
    // 示例:添加一个修改pages的方法
    func addPage() {
        model.pages.append(model.pages.count + 1)
    }
}

最后调整DetailView,因为DetailViewModel现在是引用类型,建议用@StateObject来管理:

struct DetailView: View {
    @StateObject private var viewModel: DetailViewModel
    
    init(viewModel: DetailViewModel) {
        _viewModel = StateObject(wrappedValue: viewModel)
    }
    
    var body: some View {
        VStack {
            Text("Detail View")
            Button("Add Page") {
                viewModel.addPage()
            }
        }
    }
}

这样点击DetailView里的按钮,model.pages的变化会同步回ContentView,视图也会自动刷新。

方法二:使用Binding(适合简单父子视图传递)

如果你不想把模型改成类,也可以用SwiftUI的Binding来让视图模型间接修改原数据。这种方式适合仅在父子视图之间传递修改的场景。

首先保持MyModel为struct不变,修改DetailViewModel,让它持有Binding<MyModel>:

class DetailViewModel: ObservableObject {
    private let modelBinding: Binding<MyModel>
    
    // 通过binding获取当前模型数据
    var model: MyModel {
        modelBinding.wrappedValue
    }
    
    init(modelBinding: Binding<MyModel>) {
        self.modelBinding = modelBinding
    }
    
    // 示例:修改pages的方法
    func addPage() {
        modelBinding.wrappedValue.pages.append(model.pages.count + 1)
    }
}

然后调整ContentView里的NavigationLink,把model的Binding传给DetailView:

NavigationLink("Details") {
    DetailView(viewModel: DetailViewModel(modelBinding: $model))
}

最后修改DetailView的初始化(现在不需要@autoclosure了,直接传ViewModel实例即可):

struct DetailView: View {
    @StateObject private var viewModel: DetailViewModel
    
    init(viewModel: DetailViewModel) {
        _viewModel = StateObject(wrappedValue: viewModel)
    }
    
    var body: some View {
        VStack {
            Text("Detail View")
            Button("Add Page") {
                viewModel.addPage()
            }
        }
    }
}

这样点击按钮时,通过Binding修改的是ContentView里的原模型数据,同样能实现同步更新。

两种方案各有优劣:如果模型状态需要跨多个组件共享,推荐用Class+ObservableObject;如果只是简单的父子视图交互,Binding更轻量。你可以根据自己的需求选择~

备注:内容来源于stack exchange,提问作者JAHelia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 02:44:53