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

SwiftUI中如何在两个ViewModel间共享已发布的模型?

解决多ViewModel共享并同步修改同一模型的问题

你的核心问题在于值类型的Model被拷贝传递,导致两个ViewModel持有独立的实例,修改无法同步;同时直接用Binding无法让ViewModel感知到变更并通知视图更新。下面给你两种最实用的解决方案:

方案一:将Model改为ObservableObject(推荐)

把原本的struct Model改成class并遵循ObservableObject,这样它就变成了引用类型,两个ViewModel会持有同一个实例,修改时自动同步所有关联视图。

修改后的代码如下:

1. 重构Model为ObservableObject

import SwiftUI
import Combine

class Model: ObservableObject {
    @Published var name = ""
}

2. 更新ContentView1及其ViewModel

struct ContentView1: View {
    @StateObject var contentView1Model = ContentView1Model()
    
    var body: some View {
        NavigationView {
            VStack{
                // 直接绑定到Model的@Published属性,自动同步
                TextField("ModelName", text: $contentView1Model.model.name)
                NavigationLink(
                    destination: ContentView2(model: contentView1Model.model)
                ){
                    Text("ToContentView2")
                }
            }
        }
    }
}

class ContentView1Model: ObservableObject {
    // 不需要@Published,因为Model自己会发布变更通知
    let model: Model
    
    init() {
        self.model = Model()
    }
    
    // 示例:修改Model的方法
    func resetName() {
        model.name = ""
    }
}

3. 更新ContentView2及其ViewModel

struct ContentView2: View {
    @StateObject var contentView2Model: ContentView2Model
    
    init(model: Model) {
        self._contentView2Model = StateObject(wrappedValue: ContentView2Model(model: model))
    }
    
    var body: some View {
        TextField("ModelName", text: $contentView2Model.model.name)
    }
}

class ContentView2Model: ObservableObject {
    let model: Model
    
    init(model: Model) {
        self.model = model
    }
    
    // 示例:修改Model的方法
    func appendSuffix() {
        model.name += " (from View2)"
    }
}

为什么这样有效?

  • Model变成引用类型后,传递给ContentView2Model的是同一个实例,修改任何一个ViewModel里的Model都会直接改变原对象
  • Model的@Published属性会自动向所有绑定的视图发送变更通知,确保UI实时更新

方案二:用共享Store管理Model(保持Model为struct)

如果你必须保持Model为值类型,可以创建一个共享的ModelStore(ObservableObject)来持有Model,让两个ViewModel都引用这个Store,确保操作的是同一个Model实例。

1. 创建共享Store

class ModelStore: ObservableObject {
    @Published var model = Model() // Model还是原来的struct
}

// 原Model结构不变
struct Model {
    var name = ""
}

2. 更新ContentView1及其ViewModel

struct ContentView1: View {
    @StateObject private var store = ModelStore()
    @StateObject private var contentView1Model: ContentView1Model
    
    init() {
        let store = ModelStore()
        self._store = StateObject(wrappedValue: store)
        self._contentView1Model = StateObject(wrappedValue: ContentView1Model(store: store))
    }
    
    var body: some View {
        NavigationView {
            VStack{
                TextField("ModelName", text: $contentView1Model.store.model.name)
                NavigationLink(
                    destination: ContentView2(store: store)
                ){
                    Text("ToContentView2")
                }
            }
        }
    }
}

class ContentView1Model: ObservableObject {
    let store: ModelStore
    
    init(store: ModelStore) {
        self.store = store
    }
    
    func updateName(_ newName: String) {
        store.model.name = newName
    }
}

3. 更新ContentView2及其ViewModel

struct ContentView2: View {
    @ObservedObject var store: ModelStore
    @StateObject private var contentView2Model: ContentView2Model
    
    init(store: ModelStore) {
        self.store = store
        self._contentView2Model = StateObject(wrappedValue: ContentView2Model(store: store))
    }
    
    var body: some View {
        TextField("ModelName", text: $contentView2Model.store.model.name)
    }
}

class ContentView2Model: ObservableObject {
    let store: ModelStore
    
    init(store: ModelStore) {
        self.store = store
    }
    
    func modifyName() {
        store.model.name += " [Edited in View2]"
    }
}

为什么这样有效?

  • 所有ViewModel共享同一个ModelStore实例,操作的是Store里的同一个Model
  • Store的@Published var model会在Model值变化时自动通知所有视图更新

为什么你原来的方式行不通?

  1. 值类型拷贝:你的Model是struct(值类型),传递给ContentView2Model时会生成一个新的拷贝,两个ViewModel的Model完全独立,修改互不影响
  2. Binding无法触发ViewModel发布:即使你用Binding传递Model,ViewModel作为ObservableObject,Binding的变更不会自动触发objectWillChange事件,视图无法感知到ViewModel内的修改

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:34:52