My guess is SwiftUI marks part of view hierarchy as "dirty" in willSet, then redraw it during render pass. Observability in its current state tailored for this specific approach.
I believe it’s just the old performSelector:afterDelay:0 and cancelPreviousPerformRequestsWithTarget: pattern to debounce (or coalesce) the updates. Thus no matter how many things send change notifications, SwiftUI will only recompute View structs once on the next run loop.
The weird thing here is because Observables observe themselves that’s a retain cycle. Also if one never changes after tracking itself that’s a leak, eg if a View is removed.
+1. I also have this same observation.
Update: this observation was based on early versions of the implementation, I believe the latest implementation can cancel all observations automatically.
I think I have the impression that the current form of observation makes it not suitable for use manually, it just serves some specific UI frameworks (eg. SwiftUI) better.
Not sure if related, but if you are accessing a property of an Observable class from inside a SwiftUI's TimelineView your application memory usage will continously increase at frame rates.
Seems it serves SwiftUI worse than ObservableObject
. With an @State
struct accessed in body, a change to any var is seen as a change to the whole @State
. Same behaviour with @StateObject
and its @Published vars
. With this new @Observable
the semantics have changed to per property instead of per instance which breaks the consistency AND it leaks all over the place. E.g. the is leak that required an extra property added to the object: @duan.ca on Bluesky
I actually brought this up to a few engineers from Apple at the SwiftUI summit these last two days. Because the withObservationTracking
that accepts willSet
and didSet
are @_spi(SwiftUI)
(for now)… it's not completely clear what a "evolution" looks like to then just remove that spi
and launch this as a legit "public" API. Would that be something that would need an internal SwiftUI approval? Would the community just make that decision to approve and then SwiftUI just has to go along with what the community wants?
The consensus I heard seems to be that yes the decision to launch willSet
and didSet
should be driven by the open-source evolution review and approval process.
I'm not personally blocked on willSet
and didSet
… but I know a lot of engineers are blocked on migrating from Combine and launching this to public would help those engineers move to Observable
without all the workarounds.