I found a solution from two parts:
- This gist that returns a publisher for a given keypath. The downside is there's no way to limit the keypath parameter to @ObservationTracked keypaths only, so a publisher can be formed for @ObservationIgnored keypaths.
- This gist from @jasdev that lets you assign to weakly captured self, as Combine's
assign(to:on:)
captures its object strongly.
Thanks to it, my observable model now looks like this:
@Observable final class ObservableCalculator {
var a: Int
var b: Int
private(set) var sum: Int
private var cancellables: Set<AnyCancellable> = []
init(a: Int = 0, b: Int = 0) {
self.a = a
self.b = b
self.sum = a + b
publisher(keyPath: \.a)
.combineLatest(publisher(keyPath: \.b))
.map(+)
.assign(to: \.sum, onWeaklyCaptured: self)
.store(in: &cancellables)
}
}
It still needs Combine to work and uses the recursive call to withObservationTracking
under the hood, and does not address the fact that continued observation is still required in the library.
Edit: Welp never mind I may have spoken too soon. It does not seem to work.