[Second review] SE-0395: Observability

With the current proposal, there lacks a way for the caller to express that it no longer cares about the update from the previous withObservationTracking (like a View is dismissed), or for the Observable object to express that changes are no longer possible (like when the underlying object is deallocated) so the observation tracking should stop.

Without those, it appears that it's not really possible for the implementation of withObservationTracking to correctly release the resources when either situation happens (in fact it seems like the current implementation bundled with Xcode 15 beta 1 leaks the _ManagedCriticalState on every SwiftUI view dismiss :sweat_smile: FB12294637).

Here is another example where a seemingly innocent use of the API can actually leak resources.

@Observable
class TestObject {

    var value = 1
}

@MainActor
struct Renderer {

    let viewModel = TestObject()

    func render() {
        withObservationTracking {
            print(viewModel.value)
        } onChange: {
            Task { @MainActor in
                schedule()
            }
        }
    }

    func schedule() {
        render()
    }
}

Here if someone creates a Renderer object, and call render on it, later set the reference of Renderer to nil, the object and associated resources will not get released.

Maybe the proposal should consider introducing some kind of scope for withObservationTracking so the lifecycle of the observation can be better managed?

1 Like