4.8 KiB
4.8 KiB
SwiftData to CloudKit Sync Requirements (Reusable)
Primary source of truth lives in Bedrock:
/Users/mattbruce/Documents/Projects/iPhone/Andromida/Bedrock/Sources/Bedrock/Storage/SWIFTDATA_CLOUDKIT_SETUP_GUIDE.md
This Andromida copy is app-facing reference material and should stay aligned with the Bedrock guide.
Use this checklist for any iOS app that uses SwiftData with CloudKit and requires near-real-time multi-device sync.
1) Capabilities and Entitlements
- Enable
iCloudwithCloudKitfor the app target. - Enable
Push Notificationsfor the app target. - Enable
Background Modes > Remote notifications. - Add App Group if app + widget share local SQLite.
Required entitlement keys:
com.apple.developer.icloud-container-identifierscom.apple.developer.icloud-servicesincludingCloudKitcom.apple.developer.ubiquity-kvstore-identifier(if KVS is used)aps-environment(must resolve per config)com.apple.security.application-groups(if widget/app group storage is used)
2) Build Configuration
Use xcconfig variables so environments are explicit and portable:
- Debug:
APS_ENVIRONMENT = development - Release:
APS_ENVIRONMENT = production
Entitlements should reference variables, not hard-coded values, where possible.
3) Model and Schema Constraints (SwiftData + CloudKit)
- Avoid
@Attribute(.unique)in CloudKit-mirrored models. - Ensure all stored properties have defaults or are optional.
- Keep relationships optional for CloudKit compatibility.
- Use additive schema evolution only (add fields/models; do not remove/rename/change types in place).
4) Runtime Sync Behavior
- Prefer Bedrock
SwiftDataCloudKitSyncManageras the reusable remote observer/lifecycle component. - Prefer Bedrock
SwiftDataStore+SwiftDataCloudKitStoreto avoid app-specific pulse boilerplate. - Observe
.NSPersistentStoreRemoteChangeto detect remote merges. - Use Bedrock
startObservingCloudKitRemoteChanges(...)for default remote-change handling. - Rebuild long-lived contexts only when safe (
hasChanges == false) to avoid dropping unsaved local edits. - Implement protocol reload hook (
reloadData) to run your store-specific fetch step. - Prefer Bedrock
saveAndReload()+ protocol hooks (didSaveAndReloadData,handleSaveAndReloadError) instead of local save wrappers. - Prefer Bedrock
SwiftDataCloudKitSceneSyncCoordinatorfor active/background fallback scheduling instead of app-local task orchestration. - Keep iOS-on-Mac pulsing loop in the root scene lifecycle (
activeonly, cancel onbackground). - Keep a foreground fallback refresh as a safety net; gate it with Bedrock
hasReceivedRemoteChange(since:). - Emit structured logs for remote sync events (event count + timestamp) for debugging.
5) UI Freshness Requirements
- UI must re-render on each remote merge, even for batched updates.
- Keep an observable refresh version/counter and increment on each successful reload.
- Ensure list/detail views do not rely on stale assumptions when models are updated remotely.
- Make high-frequency interaction rows fully tappable to reduce missed user actions.
6) Verification Matrix
Test all cases on two physical devices with the same Apple ID and same app flavor:
- Single toggle on Device A appears on Device B while both apps are open.
- Rapid batch toggles on Device A all appear on Device B without manual pull-to-refresh.
- Device B in background receives updates after foregrounding (without force quit).
- Airplane mode recovery syncs correctly after reconnection.
- Simultaneous edits resolve predictably (CloudKit last-writer-wins).
7) Observability and Console Checks
- Device logs: filter by sync logger category (for example
CloudKitSync). - CloudKit Console: validate record updates in the app container private database.
- If pushes are delivered but UI is stale, investigate context freshness and view invalidation, not transport.
- If APNs is unreliable on Mac runtime, validate that pulse logs appear every interval while active.
8) Reuse Checklist for New Apps
Before shipping any new SwiftData+CloudKit app:
- Capabilities: iCloud/CloudKit + Push + Remote Notifications are enabled
- Entitlements include
aps-environmentand correct container IDs - xcconfig defines
APS_ENVIRONMENTper configuration - Remote change observer uses Bedrock
startObservingCloudKitRemoteChanges(...) - Store conforms to Bedrock
SwiftDataCloudKitStore - Save flows use Bedrock
saveAndReload()and protocol hooks (no local wrapper duplication) - Scene-phase fallback scheduling uses Bedrock
SwiftDataCloudKitSceneSyncCoordinator - Foreground fallback is gated by Bedrock
hasReceivedRemoteChange(since:) - UI has deterministic invalidation on remote reload
- Two-device batch-update test passes without manual refresh
- CloudKit Console verification documented in README/PRD