Categories
ios observable swift swiftui

How to listen to an ObservableObject

Ok, so SwiftUI and ObservableObject, on iOS 13. I have Model that implements 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)")
}
}
}

and a Button that toggles toggle:

struct ContentView: View {
@ObservedObject var model: Model

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

Now, this works. You hit the button and it toggles between “on” and “off”. (Before making toggle @Published, it did not.) However, the logging does not work as expected. I get two logs immediately on startup: “Model init” and “2 toggle false -> false”. Tapping the button, though apparently changing the value of toggle, does not cause either of the closures to execute.

When the view mutates your model, I’d expect there to be a way to be informed of the change, in case you need to e.g. update calculated values or sync to disk or something. Perhaps sink is the wrong method?

How can an ObservableObject with @Published fields be notified when its fields are updated?