将一个可观察对象模型传递到另一个观察对象?



我觉得我可以理解为什么我正在做的事情不起作用,但我仍然试图围绕 Combine 和 SwiftUI 进行思考,所以欢迎在这里提供任何帮助。

请考虑以下示例:

在 UserDefault 中存储一些字符串的单一视图应用,并使用这些字符串显示一些文本标签。有三个按钮,一个用于更新标题,另一个用于将两个 UserDefaults 存储的字符串更新为随机字符串。

该视图是哑渲染器视图,标题字符串直接存储在 ObservableObject 视图模型中。视图模型具有一个已发布的属性,该属性包含对 UserSettings 类的引用,该类实现属性包装器以将用户定义的字符串存储到 UserDefaults。

观察:

• 点击"设置新标题"可正确更新视图以显示新值

• 点击任一"设置用户值"按钮确实会在内部更改值,但视图不会刷新。 如果在其中一个按钮之后点击"设置新标题",则当视图主体为标题更改重新生成时,将显示新值。

视图:

import SwiftUI
struct ContentView: View {
@ObservedObject var model = ViewModel()
var body: some View {
VStack {
Text(model.title).font(.largeTitle)
Form {
Section {
Text(model.settings.UserValue1)
Text(model.settings.UserValue2)
}
Section {
Button(action: {
self.model.title = "Updated Title"
}) { Text("Set A New Title") }
Button(action: {
self.model.settings.UserValue1 = "(Int.random(in: 1...100))"
}) { Text("Set User Value 1 to Random Integer") }
Button(action: {
self.model.settings.UserValue2 = "(Int.random(in: 1...100))"
}) { Text("Set User Value 2 to Random Integer") }
}
Section {
Button(action: {
self.model.settings.UserValue1 = "Initial Value One"
self.model.settings.UserValue2 = "Initial Value Two"
self.model.title = "Initial Title"
}) { Text("Reset All") }
}
}
}
}
}

视图模型:

import Combine
class ViewModel: ObservableObject {
@Published var title = "Initial Title"
@Published var settings = UserSettings()
}

用户设置模型:

import Foundation
import Combine
@propertyWrapper struct DefaultsWritable<T> {
let key: String
let value: T
init(key: String, initialValue: T) {
self.key = key
self.value = initialValue
}
var wrappedValue: T {
get { return UserDefaults.standard.object(forKey: key) as? T ?? value }
set { return UserDefaults.standard.set(newValue, forKey: key) }
}
}

final class UserSettings: NSObject, ObservableObject {
let objectWillChange = PassthroughSubject<Void, Never>()
@DefaultsWritable(key: "UserValue", initialValue: "Initial Value One") var UserValue1: String {
willSet {
objectWillChange.send()
}
}
@DefaultsWritable(key: "UserBeacon2", initialValue: "Initial Value Two") var UserValue2: String {
willSet {
objectWillChange.send()
}
}
}

当我在用户设置中willSet { objectWillChange.send() }上放置断点时,我看到 objectWillChange 消息在我期望它时发送给发布者,以便告诉我问题可能是视图或视图模型未正确订阅它。我知道如果我在视图上将用户设置作为@ObservedObject,这将起作用,但我觉得这应该在带有 Combine 的视图模型中完成。

我在这里错过了什么?我相信这真的很明显...

ObsesrvedObject侦听@Published属性的变化,但不侦听更深层次的内部发布者,所以下面的思路是加入内部发布者,这是PassthroughSubject,与@Published var settings,以表明后者已经更新。

与Xcode 11.2/iOS 13.2兼容

唯一需要的更改是ViewModel...

class ViewModel: ObservableObject {
@Published var title = "Initial Title"
@Published var settings = UserSettings()
private var cancellables = Set<AnyCancellable>()
init() {
self.settings.objectWillChange
.sink { _ in
self.objectWillChange.send()
}
.store(in: &cancellables)
}
}

最新更新