Swift 两个可观测对象之间的数据通信

Swift 两个可观测对象之间的数据通信,swift,swiftui,combine,observableobject,data-communication,Swift,Swiftui,Combine,Observableobject,Data Communication,我有两个独立的observeObjects,分别称为ViewModel1和ViewModel2 ViewModel2有一个字符串数组: @已发布的变量字符串:[String]=[] 无论何时修改该数组,我都希望通知ViewModel1 实现这一点的推荐方法是什么?我也遇到了同样的问题,我发现这个方法很好地工作,只是使用了引用类型的概念,并像使用共享类型一样利用类 import SwiftUI struct ContentView: View { @StateObject va

我有两个独立的
observeObject
s,分别称为
ViewModel1
ViewModel2

ViewModel2
有一个字符串数组:

@已发布的变量字符串:[String]=[]

无论何时修改该数组,我都希望通知
ViewModel1


实现这一点的推荐方法是什么?

我也遇到了同样的问题,我发现这个方法很好地工作,只是使用了引用类型的概念,并像使用共享类型一样利用类

import SwiftUI

struct ContentView: View {
    
    @StateObject var viewModel2: ViewModel2 = ViewModel2.shared
    @State var index: Int = Int()
    
    var body: some View {

        Button("update strings array of ViewModel2") {

            viewModel2.strings.append("Hello" + index.description)
            index += 1
        }

        
    }
}


class ViewModel1: ObservableObject {
    
    static let shared: ViewModel1 = ViewModel1()
    
    @Published var onReceiveViewModel2: Bool = Bool() {
        
        didSet {
        
            print("strings array of ViewModel2 got an update!")
            print("new update is:", ViewModel2.shared.strings)

        }
        
    }
    
}


class ViewModel2: ObservableObject {
    
    static let shared: ViewModel2 = ViewModel2()
    
    @Published var strings: [String] = [String]() {
        
        didSet { ViewModel1.shared.onReceiveViewModel2.toggle() }
        
    }
    
}

显然,有很多潜在的解决方案,比如前面提到的
通知中心
和单例思想

对我来说,这似乎是一个联合收割机非常有用的场景:

import SwiftUI
import Combine

class ViewModel1 : ObservableObject {
    var cancellable : AnyCancellable?
    
    func connect(_ publisher: AnyPublisher<[String],Never>) {
        cancellable = publisher.sink(receiveValue: { (newStrings) in
            print(newStrings)
        })
    }
}

class ViewModel2 : ObservableObject {
    @Published var strings: [String] = []
}


struct ContentView : View {
    @ObservedObject private var vm1 = ViewModel1()
    @ObservedObject private var vm2 = ViewModel2()
    
    var body: some View {
        VStack {
            Button("add item") {
                vm2.strings.append("\(UUID().uuidString)")
            }
            
            ChildView(connect: vm1.connect)
            
        }.onAppear {
            vm1.connect(vm2.$strings.eraseToAnyPublisher())
        }
    }
}

struct ChildView : View {
    var connect : (AnyPublisher<[String],Never>) -> Void
    @ObservedObject private var vm2 = ViewModel2()
    
    var body: some View {
        Button("Connect child publisher") {
            connect(vm2.$strings.eraseToAnyPublisher())
            vm2.strings = ["Other strings","From child view"]
        }
    }
}

导入快捷界面
进口联合收割机
类ViewModel1:ObservableObject{
var可取消:任何可取消?
func connect(upublisher:AnyPublisher){
Cancelable=publisher.sink(receiveValue:{(新闻字符串)在
印刷品(新闻串)
})
}
}
类ViewModel2:ObservableObject{
@已发布的变量字符串:[String]=[]
}
结构ContentView:View{
@ObservedObject私有变量vm1=ViewModel1()
@ObservedObject私有变量vm2=ViewModel2()
var body:一些观点{
VStack{
按钮(“添加项目”){
追加(\(UUID().UUIString)”)
}
子视图(连接:vm1.connect)
}奥纳佩尔先生{
vm1.connect(vm2.$strings.eraseToAnyPublisher())
}
}
}
结构子视图:视图{
var connect:(AnyPublisher)->Void
@ObservedObject私有变量vm2=ViewModel2()
var body:一些观点{
按钮(“连接子发布服务器”){
连接(vm2.$strings.eraseToAnyPublisher())
vm2.strings=[“其他字符串”,“来自子视图”]
}
}
}
要测试这一点,首先尝试按下“添加项”按钮——您将在控制台中看到
ViewModel1
接收新值

然后,尝试
连接子发布者
按钮——现在,初始连接被取消,并且对子发布者的
视图模型2
迭代创建了一个新的连接

为了使此场景正常工作,您必须始终引用
ViewModel1
ViewModel2
,或者至少引用
connect
方法,如我在
ChildView
中所示。您可以通过依赖项注入或甚至通过
EnvironmentObject


ViewModel1
也可以更改为,而不是只有一个连接,通过将
设置为可取消的
Set
并在需要一个->多个场景时每次添加一个连接,可以拥有多个连接


使用
AnyPublisher
可以将等式两边都有特定类型的想法分离开来,因此将
ViewModel4
连接到
ViewModel1
等也同样容易。

ViewModel1
可以订阅
strings
中的更改,例如
viewModel2.$strings.sink{…}
可能会有很多,你能更具体地描述一下你的背景吗?@Asperi不知道在不太详细的情况下我能有多具体。就像我写的,它们是两个独立的类,处理着非常不同的职责。但是我需要第一个类在第二个类中的某些内容发生更改时得到通知。如果您想保持它们的独立性,请使用NotificationCenter@Asperi我认为NotificationCenter不适合,因为只有ViewModel1对这些更改感兴趣。我所说的独立是指不同的班级有不同的职责。