Tom Insam

Easy watching of @Observable object properties from Swift

I’ve been experimenting migrating Flame from ObservableObject to Observable.

It’s very simple to have SwiftUI watch these obejcts for changes, but because of the legacy navigation I have in the app, I rely on the ability to watch the object for changes from normal Swift code. Previously I was subscribing to the Combine publishers for this, but now that I’ve moved to the new macro, I’ve been missing this simple functionality.

Here’s a simple extension that makes this easier:

public func observeObject<T: Observable & AnyObject, S>(
    _ object: T,
    keypath: KeyPath<T, S>,
    onChange: @escaping (S) -> Void
) {
    withObservationTracking {
        _ = object[keyPath: keypath]
    } onChange: { [weak object] in
        guard let object else { return }
        Task { @MainActor in
            onChange(object[keyPath: keypath])
            observeObject(object, keypath: keypath, onChange: onChange)
        }
    }
}

And here’s how you use it:

observeObject(viewModel, keypath: \.selection) { [weak self] selection in
    self?.valueDidChange(selection)
}

The Flame codebase change is here.