【问题标题】:How to listen to an ObservableObject如何监听 ObservableObject
【发布时间】:2020-01-22 03:16:41
【问题描述】:

好的,所以 SwiftUIObservableObject 在 iOS 13 上。我有实现 ObservableObjectModel

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)")
        }
    }
}

和一个切换toggle的按钮:

struct ContentView: View {
    @ObservedObject var model: Model
    
    var body: some View {
        Button(action: {
            self.model.toggle.toggle()
        }, label: {Text(model.toggle ? "on" : "off")})
    }
}

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

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

如何在更新其字段时通知带有@Published 字段的ObservableObject

【问题讨论】:

    标签: ios swift observable swiftui


    【解决方案1】:

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

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

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

    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)")
            }
        }
    }
    

    我没有使用太多Combine,但我经常看到的另一种选择是您可能会考虑将didSet 添加到您的属性中,如下所示:

        public var toggle: Bool = false {
            didSet {
                print("1 toggle \(self.toggle)")
            }
        }
    

    【讨论】:

    • 啊,这就是我所缺少的!谢谢!有时我可能会使用didSet,但知道如何使用objectWillChange 一次监控所有内容也很好。 objectDidChange 也可能不错,但我不认为这是给我们的,至少默认情况下是这样。
    【解决方案2】:

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

    1. ObjectWillChange 应该是 ObservableObjectPublisher() 类型

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

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

     var toggle = "" {
            willSet {
                objectWillChange.send()
            }
        }
    

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

    3.确保您的模型类符合 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")})
        }
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-23
      • 1970-01-01
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 2011-08-21
      • 2012-11-18
      相关资源
      最近更新 更多