Complete reference for USB Meter's multi-device synchronization system using CloudKit.
Problem: How do settings sync across my iPhone, iPad, and Mac?
Answer:
1. When you connect a meter on iPhone → Meter.swift calls appData.publishMeterConnection()
2. This updates a DeviceSettings record in Core Data
3. NSPersistentCloudKitContainer automatically syncs it to iCloud
4. Your iPad + Mac receive a notification → refresh UI
5. Within 2-5 seconds, all devices show "Connected on iPhone"
uniquenessConstraint was removedRead this if: You need to understand the data structure, add fields, or debug data corruption.
Read this if: You're troubleshooting sync issues, understanding threading, or extending functionality.
Read this if: Sync isn't working, you want to add debug UI, or need production troubleshooting.
Represents a single Bluetooth meter device with its metadata:
macAddress: "aa:bb:cc:dd:ee:ff" ← identifies the meter
meterName: "Kitchen Meter" ← user-friendly name
modelType: "TC66C" ← hardware type
connectedByDeviceID: "UUID" ← which device is using it now
connectedExpiryAt: Date ← connection lock TTL (120s)
updatedAt: Date ← last sync timestamp
publishMeterConnection() → saves record → syncsclearMeterConnection() → clears record → syncsreloadSettingsFromCloudStore() to check for remote changesIf Device A and B edit the same record simultaneously:
- Policy: NSMergeByPropertyStoreTrumpMergePolicy
- Rule: CloudKit's version always wins
- Edge case: User might see their local change revert (~1s after)
Meter UI ──→ BT Connection ──→ AppData ──→ CloudDeviceSettingsStore ──→ Core Data
↓ ↓
[CloudKit Sync] [persisted locally]
↓
[iCloud Servers]
↓
Other Devices ──→ UI Updates
| File | Role |
|---|---|
AppDelegate.swift |
Creates NSPersistentCloudKitContainer (line 85-127) |
SceneDelegate.swift |
Calls activateCloudDeviceSync() at startup |
AppData.swift |
Orchestrates sync: publishMeterConnection, clearMeterConnection, reloadSettingsFromCloudStore |
Meter.swift |
Line 109, 118, 132: Calls appData methods on state changes |
CKModel.xcdatamodeld/USB_Meter 2.xcdatamodel/contents |
Core Data schema (no uniqueness constraint) |
USB Meter.entitlements |
iCloud container + CloudKit permissions |
.available?iCloud.ro.xdev.USB-Meter?USB_Meter 2.xcdatamodel or later?cloudStoreRebuildVersion ≥ 3?setupRemoteChangeNotificationObserver()?NSMergeByPropertyStoreTrumpMergePolicy?appData.reloadSettingsFromCloudStore()NSPersistentStoreRemoteChange notificationscloudStoreRebuildVersion = 3 deployedrebuildCanonicalStoreIfNeeded ran (UserDefaults cloudStoreRebuildVersion.3)appData.clearMeterConnection(mac: "...")setConnection()USB_Meter 2.xcdatamodel/contents → add attribute (optional!)CloudDeviceSettingsStore to populate itTotal end-to-end for a setting change: ~5-8 seconds (typical, good network)
Use two devices on same iCloud account:
Refer to specific sections above by file, or check the troubleshooting checklist in TROUBLESHOOTING.md.