如何收听 ObservableObject

Erh*_*nis 10 observable ios swift swiftui

好的,所以 SwiftUI 和 ObservableObject,在 iOS 13 上。我有实现 ObservableObject 的模型:

class Model: ObservableObject {
    @Published public var toggle: Bool = false

    init() {
        NSLog("Model init")
        objectWillChange.sink { void in
            NSLog("1 toggle \(self.toggle)")
        }
        $toggle.sink { v in
            NSLog("2 toggle \(self.toggle) -> \(v)")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和一个可以切换的按钮toggle

struct ContentView: View {
    @ObservedObject var model: Model

    var body: some View {
        Button(action: {
            self.model.toggle.toggle()
        }, label: {Text(model.toggle ? "on" : "off")})
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,这有效。你按下按钮,它会在“开”和“关”之间切换。(在 make 之前toggle @Published,它没有。)但是,日志记录没有按预期工作。我在启动时立即得到两个日志:“Model init”和“2 toggle false -> false”。点击按钮,虽然显然改变了 的值toggle,但不会导致执行任何一个闭包。

当视图改变您的模型时,我希望有一种方法可以通知更改,以防您需要更新计算值或同步到磁盘或其他内容。也许sink是错误的方法?

当字段更新时如何通知ObservableObjectwith@Published字段?

Joe*_*Joe 12

sink函数返回值的最新文档:

/// - Returns: A cancellable instance; used when you end assignment of the received value. Deallocation of the result will tear down the subscription stream.

本质上,这意味着 sink 生成 aSubscriber但不保留它。一旦您的初始化完成,订阅者就会被拆除并从内存中删除。您需要通过创建这样的强引用来保留它们:

class Model: ObservableObject {
    @Published public var toggle: Bool = false

    var changeSink: AnyCancellable?
    var toggleSink: AnyCancellable?

    init() {
        NSLog("Model init")
        changeSink = objectWillChange.sink { void in
            NSLog("1 toggle \(self.toggle)")
        }
        toggleSink = $toggle.sink { v in
            NSLog("2 toggle \(self.toggle) -> \(v)")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我用的不多,Combine但我经常看到的另一种方法是,您可能会考虑将 a 添加didSet到您的属性中,如下所示:

    @Published public var toggle: Bool = false {
        didSet {
            print("1 toggle \(self.toggle)")
        }
    }
Run Code Online (Sandbox Code Playgroud)


San*_*awi 5

您的 ObservableObject 类模型已正确完成,但是:

1. ObjectWillChange 应该是 ObservableObjectPublisher() 类型

这会创建一个 objectWillChange 属性作为 ObservableObjetPublisher 的实例。这来自于Combine 框架,这就是为什么你需要添加import Combine 来编译你的代码。可观察对象发布者的工作很简单:每当我们想告诉全世界我们的对象发生了变化时,我们都会要求发布者为我们做这件事。

2.你需要观察的属性(Toggle)应该这样实现:

 var toggle = "" {
        willSet {
            objectWillChange.send()
        }
    }
Run Code Online (Sandbox Code Playgroud)

其次,我们有一个 willSet 属性观察器附加到 Model 的 Toggle 属性,以便我们可以在该值更改时运行代码。在我们的示例代码中,每当切换更改时,我们都会调用 objectWillChange.send(),这会告诉 objectWillChange 发布者发布我们的数据已更改的消息,以便任何订阅的视图都可以刷新。

3.确保你的类Model符合ObservableObject,并且它的实例用@ObservedObject标记

由于您的模型类符合 ObservableObject,您可以像使用任何其他 @ObservedObject 属性一样使用它。因此,我们可以像这样使用它来观看切换,如下所示:

struct ContentView: View {
    @ObservedObject var model: Model

    var body: some View {
        Button(action: {
            self.model.toggle.toggle()
        }, label: {Text($model.toggle ? "on" : "off")})
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这有帮助,参考:https : //www.hackingwithswift.com/quick-start/swiftui/how-to-send-state-updates-manually-using-objectwillchange