swift - 2 个 ObservableObjects 之间的数据通信
问题描述
我有 2 个独立ObservableObject
的 sViewModel1
和ViewModel2
。
ViewModel2
有一个字符串数组:
@Published var strings: [String] = []
.
每当修改该数组时,我都想ViewModel1
被告知。
实现这一目标的推荐方法是什么?
解决方案
显然,有很多潜在的解决方案,比如前面提到的NotificationCenter
和单例的想法。
对我来说,这似乎是一个组合相当有用的场景:
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
接收新值。
然后,试试这个Connect child publisher
按钮——现在,初始连接被取消,并为孩子的ViewModel2
.
为了使这个场景起作用,您总是必须引用ViewModel1
and ViewModel2
,或者至少引用该connect
方法,正如我在 中演示的那样ChildView
。您可以通过依赖注入甚至通过EnvironmentObject
ViewModel1
如果您需要一个 -> 多个场景,也可以更改为而不是拥有 1 个连接,而是通过创建一个连接并每次添加一个连接来拥有多个cancellable
连接Set<AnyCancellable>
。
使用AnyPublisher
解耦了等式两边都有特定类型的想法,因此连接ViewModel4
到ViewModel1
等同样容易。
推荐阅读
- github-actions - 是否可以使用 fnmatch 模式来匹配语义版本?
- mariadb - Vagrant 规定添加 mariaDB apt key 错误
- python-3.x - 在不更改函数值的情况下解决内存错误的最佳方法是什么?
- kendo-ui - Kendo MVC 图表 - 如何在加载数据时显示动画?
- c# - 如何检查字符串是否包含单词并忽略特殊字符?
- api - .netcore 会话变量始终为空
- oauth - 在谷歌工作区上使用内部测试应用程序时,令牌在 7 天内过期是否有问题?
- spring-boot - 运行构建时,如何将 Fat Jar 复制到 rpm 文件夹中作为备用目录?
- yarnpkg - 当 javascript 库完整性与远程存储库不同时使纱线缓存无效
- swift - SwiftUI 和 UIKit:存储选择的方向并相应地旋转设备