0.9.0
What's Changed
CoreDataEvolution 0.9.0 adds opt-in MainActor Swift Observation for generated Core Data models.
- Add
@PersistentModel(observation: .mainActor)for iOS 17+ / macOS 14+ platform families. - Add
CDEObservationDomain, a retained container-bound runtime that activates observation routing forcontainer.viewContext. - Let SwiftUI and
withObservationTrackingread CoreDataEvolution-generated Core Data accessors directly, including relationship chains, without forcing extraObservableObjectprojection layers into view structure. - Route saved changes with property-level precision when the producer can provide changed Core Data keys.
- Support precise routes for plain
viewContext.save(),NSModelActor.saveObservedChanges(in:),NSMainModelActor.saveObservedChanges(in:), registered ordinary background contexts, and wrapper-owned context saves. - Add lifecycle and fallback handling for rollback, refresh, reset, delete, temporary object ID rekeying, batch operations, unregistered contexts, and objectID-only merges.
- Preserve precise local/background routes across store re-merges with
CDEPreciseRouteEchoSuppression, including the commonNSPersistentCloudKitContainer/ Persistent History Tracking echo. - Add
CDE_OBSERVATION_DEBUGandCDEObservationDomain.isDebugLoggingEnabledfor opt-in unified logging diagnostics. - Add the public
Docs/ObservationGuide.md, update README and DocC, and keep internal mechanism / implementation documents underDocs/Development.
Public API Highlights
PersistentModelObservationMode.mainActorCDEObservationDomain(container:preciseRouteEchoSuppression:)CDEObservationDomain.registerChangeProducer(context:)CDEObservationDomain.newObservedBackgroundContext()CDEObservationDomain.saveObservedChanges(in:)CDEObservationDomain.rollbackObservedChanges()CDEPreciseRouteEchoSuppressionNSModelActor.saveObservedChanges(in:)NSMainModelActor.saveObservedChanges(in:)
Behavior Notes
- Observation is opt-in. Plain
@PersistentModeland explicitobservation: .nonekeep the non-observable generated output. - Only CoreDataEvolution-generated accessors participate in observation. Raw
@NSManagedproperties and custom getters that bypass generated accessors are not observable. - Refresh is save-gated: generated setters write Core Data values, while SwiftUI refresh happens after save, merge, or lifecycle fallback.
- Unregistered contexts, batch operations, and external CloudKit imports fall back to objectID / all-observable-key-path invalidation when changed-key metadata is unavailable.
- Field-level precision is useful, but the main goal is cognitive clarity: SwiftUI can stay close to the persisted Core Data object graph, especially in relationship-heavy screens.
Validation
bash Scripts/run-tests.shpassed withcom.apple.CoreData.ConcurrencyDebug=1enabled: 334 tests / 44 suites.bash Scripts/test-generated-flow.shpassed: generated source unchanged, conformance and exact validation both reported 0 errors / 0 warnings, and the external generated-flow fixture built and ran successfully.