How to listen to an ObservableObject

Your ObservableObject Class Model is done correctly, But:

1. ObjectWillChange should be of type ObservableObjectPublisher().

That creates an objectWillChange property as an instance of ObservableObjetPublisher. This comes from the Combine framework, which is why you need to add import Combine to make your code compile. The job of an observable object publisher is simple: whenever we want to tell the world that our object has changed, we ask the publisher to do it for us.

2. the property you need to observe (Toggle) should be implemented this way:

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

Second, we have a willSet property observer attached to the Toggle property of Model so that we can run code whenever that value changes. In our your example code, we call objectWillChange.send() whenever toggle changes, which is what tells the objectWillChange publisher to put out the news that our data has changed so that any subscribed views can refresh.

3. make sure your class Model conforms to ObservableObject, and the its instance is marked with @ObservedObject

As Your Model class conforms to ObservableObject, you can use it just like any other @ObservedObject property. So, we might use it like this to watch the toggle, like this:

struct ContentView: View {
    @ObservedObject var model: Model

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

Hope this helps, reference: https://www.hackingwithswift.com/quick-start/swiftui/how-to-send-state-updates-manually-using-objectwillchange


The latest documentation for the the return value on the sink function:

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

Essentially this means that sink makes a Subscriber but doesn't retain it. As soon as your init is done the subscribers are torn down and removed from memory. You need to keep them around by creating a strong reference like this:

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

I haven't used much Combine but an alternative I've seen often that you might consider is just adding a didSet to your attribute like so:

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