Switch to in-memory ModelContainer for DEBUG builds. This completely avoids the persistent CoreData schema corruption we've been hitting. If the app works with in-memory storage, the code is correct and the issue is purely a CoreData persistence layer problem. Release builds will use disk-based storage once the schema is proven correct. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@@ -41,51 +41,46 @@ struct HealthProbeApp: App {
|
||
| 41 | 41 |
// ⚠️ DeviceProfile is kept local-only (not synced to CloudKit) since it's device-specific |
| 42 | 42 |
// cosmetic data (name, color tag) that should not cross devices. |
| 43 | 43 |
private static func createModelContainer() throws -> ModelContainer {
|
| 44 |
- let cloudKitModels = Schema([ |
|
| 45 |
- HealthSnapshot.self, |
|
| 46 |
- TypeCount.self, |
|
| 47 |
- YearlyCount.self, |
|
| 48 |
- SnapshotDelta.self, |
|
| 49 |
- TypeDelta.self, |
|
| 50 |
- AnomalyRecord.self, |
|
| 51 |
- ]) |
|
| 52 |
- let localModels = Schema([ |
|
| 53 |
- OperationLog.self, |
|
| 54 |
- DeviceProfile.self, |
|
| 44 |
+ // TEMPORARY: Use in-memory storage to debug SwiftData schema issues |
|
| 45 |
+ // Once working, switch to disk-based storage below |
|
| 46 |
+ let fullSchema = Schema([ |
|
| 47 |
+ HealthSnapshot.self, TypeCount.self, YearlyCount.self, |
|
| 48 |
+ SnapshotDelta.self, TypeDelta.self, AnomalyRecord.self, |
|
| 49 |
+ OperationLog.self, DeviceProfile.self, |
|
| 55 | 50 |
]) |
| 56 | 51 |
|
| 52 |
+ #if DEBUG |
|
| 53 |
+ // In-memory for development/testing (no persistence, clears on app relaunch) |
|
| 54 |
+ return try ModelContainer(for: fullSchema, configurations: [ |
|
| 55 |
+ ModelConfiguration(schema: fullSchema, isStoredInMemoryOnly: true) |
|
| 56 |
+ ]) |
|
| 57 |
+ #else |
|
| 58 |
+ // Disk-based for production |
|
| 57 | 59 |
let appSupportURL = URL.applicationSupportDirectory |
| 58 | 60 |
try FileManager.default.createDirectory(at: appSupportURL, withIntermediateDirectories: true) |
| 59 | 61 |
|
| 60 |
- let cloudConfig: ModelConfiguration |
|
| 61 |
- let localConfig = ModelConfiguration( |
|
| 62 |
- "local", |
|
| 63 |
- schema: localModels, |
|
| 64 |
- url: appSupportURL.appending(path: "HealthProbeLocal.store"), |
|
| 65 |
- cloudKitDatabase: .none |
|
| 66 |
- ) |
|
| 62 |
+ let cloudKitModels = Schema([ |
|
| 63 |
+ HealthSnapshot.self, TypeCount.self, YearlyCount.self, |
|
| 64 |
+ SnapshotDelta.self, TypeDelta.self, AnomalyRecord.self, |
|
| 65 |
+ ]) |
|
| 66 |
+ let localModels = Schema([OperationLog.self, DeviceProfile.self]) |
|
| 67 | 67 |
|
| 68 |
- // Use local storage for now. CloudKit sync requires the container to be |
|
| 69 |
- // set up in Apple Developer Portal first. To enable CloudKit: |
|
| 70 |
- // 1. Create a CloudKit container "iCloud.ro.xdev.HealthProbe" in Developer Portal |
|
| 71 |
- // 2. Enable iCloud capability for this app |
|
| 72 |
- // 3. Replace .none with .private("iCloud.ro.xdev.HealthProbe")
|
|
| 73 |
- cloudConfig = ModelConfiguration( |
|
| 68 |
+ let cloudConfig = ModelConfiguration( |
|
| 74 | 69 |
"cloud", |
| 75 | 70 |
schema: cloudKitModels, |
| 76 | 71 |
url: appSupportURL.appending(path: "HealthProbeCloud.store"), |
| 77 | 72 |
cloudKitDatabase: .none |
| 78 | 73 |
) |
| 74 |
+ let localConfig = ModelConfiguration( |
|
| 75 |
+ "local", |
|
| 76 |
+ schema: localModels, |
|
| 77 |
+ url: appSupportURL.appending(path: "HealthProbeLocal.store"), |
|
| 78 |
+ cloudKitDatabase: .none |
|
| 79 |
+ ) |
|
| 79 | 80 |
|
| 80 |
- let fullSchema = Schema([ |
|
| 81 |
- HealthSnapshot.self, TypeCount.self, YearlyCount.self, |
|
| 82 |
- SnapshotDelta.self, TypeDelta.self, AnomalyRecord.self, |
|
| 83 |
- OperationLog.self, DeviceProfile.self, |
|
| 84 |
- ]) |
|
| 85 | 81 |
do {
|
| 86 | 82 |
return try ModelContainer(for: fullSchema, configurations: [cloudConfig, localConfig]) |
| 87 | 83 |
} catch {
|
| 88 |
- // Recover from schema migration failures by removing the stores and retrying once |
|
| 89 | 84 |
let candidates: [URL] = [ |
| 90 | 85 |
appSupportURL.appending(path: "HealthProbeCloud.store"), |
| 91 | 86 |
appSupportURL.appending(path: "HealthProbeCloud.store.shm"), |
@@ -97,5 +92,6 @@ struct HealthProbeApp: App {
|
||
| 97 | 92 |
for url in candidates { try? FileManager.default.removeItem(at: url) }
|
| 98 | 93 |
return try ModelContainer(for: fullSchema, configurations: [cloudConfig, localConfig]) |
| 99 | 94 |
} |
| 95 |
+ #endif |
|
| 100 | 96 |
} |
| 101 | 97 |
} |