Skip to content

2.1.0

Choose a tag to compare

@will-lumley will-lumley released this 06 Sep 08:02
· 2 commits to main since this release
89db10d

Fixes observed(_:) dropping property changes permanently.

Fixed

Changes landing during re-registration were lost. withObservationTracking cancels tracking the moment onChange returns, and re-registration was deferred into a Task. A mutation arriving in that window was never reported, and the stream stayed silent until some later mutation happened — if none did, the change was never delivered at all. Re-arming is now synchronous; only the read stays deferred, because onChange runs during willSet before the new value is stored.

Reads could beat the store on non-main-actor models. The deferred read was hardcoded to the main actor, which orders it after the store only when the mutation also happened there. A model on another actor could be read before its new value landed.

Added

observed(_:isolation:) and observedRelay(_:isolation:) take the actor that owns the model, defaulting to MainActor.shared. Pass your own actor if the model lives on one — the object must be mutated on whichever actor you pass.

Behaviour changes

  • The stream is no longer de-duplicated. Every change is now reported, so a burst of rapid mutations can deliver the same settled value more than once. Consumers treating the stream as distinct-only should compare values themselves.
  • Buffering is now explicitly .unbounded — unchanged from the previous default, just stated, since a slow consumer on a hot property is more likely to see a backlog.

Existing @MainActor code needs no changes.

Not covered

An @Observable with no isolation at all, mutated from arbitrary threads, remains unsupported: there is no actor to order the read against. Give the model an isolation and pass it via isolation:.

Full changelog: 2.0.0...2.1.0