Starting with iOS 17, the system introduced a new framework called Observation. It does make life a bit easier in the context of SwiftUI, but integration with UIKit (or simply the task of wiring together different Observable objects) can cause some problems, since the only tool available is withObservationTracker.
If you are going to build an app for iOS 26 or later, take a look at Observations; you do not need to read the rest of the article. As an alternative, you can take a look at Perception, it may be a good option.
With it, almost everything is fine except for one issue: it assumes a recursive call to itself, and there is no way to cancel it in the form in which it is proposed to be used.
I tested the following code on the iOS 17 simulator and on current operating systems, including macOS, and it works like a charm (yes, it’s as simple as it looks). If you have any comments, you are always welcome to share them.
@MainActor
final class ObservationTracker {
private let apply: () -> Void
init(_ apply: @escaping () -> Void) {
self.apply = apply
observe()
}
private func observe() {
withObservationTracking({ [weak self] in
self?.apply()
}, onChange: { [weak self] in
Task { @MainActor in
self?.observe()
}
})
}
}If you remove the reference to the object, observation will stop immediately (you can verify this in the debugger). Most importantly, do not keep strong references inside the callback. This can result in a memory leak, but that generally applies to withObservationTracker as well.
var observer: ObservationTracker?
...
observer = ObservationTracker { [weak self] in
self?.time = self?.timeModel.time
}If you need a more classic syntax with cancel, you can add some kind of flag to the onChange method that will stop the recursive call. In general, it was enough for me to simply set the object to nil.
Comments
To post a comment, please log in or create an account.
Sign In