【发布时间】:2022-07-05 10:41:35
【问题描述】:
以下是说明问题的游乐场的内容。基本上我有一个存储在UserDefaults 中的值,并由一个包装在@AppStorage 属性包装器中的变量访问。这让我可以访问View 中的更新值,但我正在寻找一种方法来监听ViewModels 和其他非View 类型中属性的变化。
我让它在下面的代码中工作,但我不确定这是不是最好的方法,我希望避免为我想要观看的每个属性声明 PassthroughSubject。
注意:我最初是 sink ObservableObject 的 objectWillChange 属性,但这将反映对象的任何更改,我想做一些更细粒度的事情。
那么有人对如何改进这项技术有任何想法吗?
import Combine
import PlaygroundSupport
import SwiftUI
class AppSettings: ObservableObject {
var myValueChanged = PassthroughSubject<Int, Never>()
@AppStorage("MyValue") var myValue = 0 {
didSet { myValueChanged.send(myValue) }
}
}
struct ContentView: View {
@ObservedObject var settings: AppSettings
@ObservedObject var viewModel: ValueViewModel
init() {
let settings = AppSettings()
self.settings = settings
viewModel = ValueViewModel(settings: settings)
}
var body: some View {
ValueView(viewModel)
.environmentObject(settings)
}
}
class ValueViewModel: ObservableObject {
@ObservedObject private var settings: AppSettings
@Published var title: String = ""
private var cancellable: AnyCancellable?
init(settings: AppSettings) {
self.settings = settings
title = "Hello \(settings.myValue)"
// Is there a nicer way to do this?????
cancellable = settings.myValueChanged.sink {
print("object changed")
self.title = "Hello \($0)"
}
}
}
struct ValueView: View {
@EnvironmentObject private var settings: AppSettings
@ObservedObject private var viewModel: ValueViewModel
init(_ viewModel: ValueViewModel) {
self.viewModel = viewModel
}
var body: some View {
Text("This is my \(viewModel.title) value: \(settings.myValue)")
.frame(width: 300.0)
Button("+1") {
settings.myValue += 1
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
【问题讨论】:
-
我建议完全删除视图模型对象并按设计使用视图结构
-
视图模型是我工作的许多客户端使用的 MVVM 架构的一部分。另外,无论是视图模型还是其他背景对象,问题仍然相同。监视由应用程序的另一部分触发的用户默认更改的最佳方式是什么? :-)