iCloud & Data

RSS for tag

Learn how to integrate your app with iCloud and data frameworks for effective data storage

CloudKit Documentation

Posts under iCloud & Data subtopic

Post

Replies

Boosts

Views

Activity

SwiftData One To Many
I'm working through the Develop In Swift tutorial at page [https://developer.apple.com/tutorials/develop-in-swift/navigation-editing-and-relationships-conclusion)] The tutorial has a one to many relationship between Friend and Movie (each friend can have at most one favorite movie and each movie can be the favorite for zero or more friends). An exercise left to the student is to use an .onDelete on the movie detail page to delete that movie as favorite. I modified the Form Form { TextField("Movie title", text: $movie.title) DatePicker("Release date", selection: $movie.releaseDate, displayedComponents: .date) if !movie.favoritedBy.isEmpty { Section("Favorited by") { ForEach(sortedFriends) { friend in Text(friend.name) } .onDelete(perform: deleteFavorites(indexes:)) } } } by adding the .onDelete clause I added private func deleteFavorites(indexes: IndexSet) { for index in indexes { context.delete(movie.favoritedBy[index]) } } to the view. This does delete the favorite movie, but it also deletes the friend. My assumption is that the selected friend should then have no favorite movie rather than being deleted There is an if in the Form that doesn't display the FAVORITED BY section if no friend has that movie as a favorite, but if I delete all the friends who had this movie as a favorite, the section remains (but is empty), until I exit the MovieDetail view and reload it There is no answer for these exercises, so I could be doing it wrong. EDIT: If I delete a movie using the app function to delete a movie, friends that have that movie as a favorite are not deleted and have their favorite movie set to None
3
0
768
Feb ’25
Can't get CloudKit to load data on cloud
The app works on a local db but when I try to make it work with iCloud I get errors that I don't understand. CoreData+CloudKit: -[NSCloudKitMirroringDelegate _performSetupRequest:]_block_invoke(1247): <NSCloudKitMirroringDelegate: 0x10664c200>: Failed to set up CloudKit integration for store: <NSSQLCore: 0x106688140> (URL: file:///var/mobile/Containers/Data/Application/20EF350F-F0FA-4132-97DA-61B60AADB101/Library/Application%20Support/default.store) <CKError 0x109430e40: "Partial Failure" (2/1011); "Failed to modify some record zones"; uuid = 82ED152A-D015-414D-BB79-AF36E5AF4A8B; container ID = "iCloud.se.Grindegard.MinaRecept"; partial errors: { com.apple.coredata.cloudkit.zone:defaultOwner = <CKError 0x109431230: "Permission Failure" (10/2007); server message = "Invalid bundle ID for container"; op = E56A3CDA393641F8; uuid = 82ED152A-D015-414D-BB79-AF36E5AF4A8B> }> what can be wrong?
3
0
58
Jul ’25
SwiftData: filtering against an array of PersistentIdentifiers
I would like to have a SwiftData predicate that filters against an array of PersistentIdentifiers. A trivial use case could filtering Posts by one or more Categories. This sounds like something that must be trivial to do. When doing the following, however: let categoryIds: [PersistentIdentifier] = categoryFilter.map { $0.id } let pred = #Predicate<Post> { if let catId = $0.category?.persistentModelID { return categoryIds.contains(catId) } else { return false } } The code compiles, but produces the following runtime exception (XCode 26 beta, iOS 26 simulator): 'NSInvalidArgumentException', reason: 'unimplemented SQL generation for predicate : (TERNARY(item != nil, item, nil) IN {}) (bad LHS)' Strangely, the same code works if the array to filter against is an array of a primitive type, e.g. String or Int. What is going wrong here and what could be a possible workaround?
3
0
117
Jun ’25
Accessing "iCloud Drive" folder in Files on iPhone from App written in Swift
I am trying to read and write a text file from an App written in Swift in XCode directly to the "iCloud Drive" folder in Files on the iPhone. The app worked readlly reading and writing to the Documents folder in the App container, and then readily to the "On My iPhone" folder in Files after adding 2 lines to the plist that I found in a search online. But I have been unable to get to the iCloud Drive folder. I found an item called "Enabling Document Storage in iCloud Drive" in "iCloud Design Guide" with additional plist entries that states "These settings allow iCloud Drive to provide public access to the files stored in your app’s container": NSUbiquitousContainers iCloud.com.example.MyApp NSUbiquitousContainerIsDocumentScopePublic NSUbiquitousContainerSupportedFolderLevels Any NSUbiquitousContainerName MyApp I think I changed the MyApp items appropriately. I have enabled iCloud in my App and the XCode General, and Signing entries. But this does not work. There are no error messages and no "Steps" shown in the "Capabilities" entry in Xcode. A little help? :-)
3
0
1.2k
Jan ’25
SwiftUI & SwiftData: Fatal Error "Duplicate keys of type" Occurs on First Launch
I'm developing a SwiftUI app using SwiftData and encountering a persistent issue: Error Message: Thread 1: Fatal error: Duplicate keys of type 'Bland' were found in a Dictionary. This usually means either that the type violates Hashable's requirements, or that members of such a dictionary were mutated after insertion. Details: Occurrence: The error always occurs on the first launch of the app after installation. Specifically, it happens approximately 1 minute after the app starts. Inconsistent Behavior: Despite no changes to the code or server data, the error occurs inconsistently. Data Fetching Process: I fetch data for entities (Bland, CrossZansu, and Trade) from the server using the following process: Fetch Bland and CrossZansu entities via URLSession. Insert or update these entities into the SwiftData context. The fetched data is managed as follows: func refleshBlandsData() async throws { if let blandsOnServer = try await DataModel.shared.getBlands() { await MainActor.run { blandsOnServer.forEach { blandOnServer in if let blandOnLocal = blandList.first(where: { $0.code == blandOnServer.code }) { blandOnLocal.update(serverBland: blandOnServer) } else { modelContext.insert(blandOnServer.bland) } } } } } This is a simplified version of my StockListView. The blandList is a @Query property and dynamically retrieves data from SwiftData: struct StockListView: View { @Environment(\.modelContext) private var modelContext @Query(sort: \Bland.sname) var blandList: [Bland] @Query var users: [User] @State private var isNotLoaded = true @State private var isLoading = false @State private var loadingErrorState = "" var body: some View { NavigationStack { List { ForEach(blandList, id: \.self) { bland in NavigationLink(value: bland) { Text(bland.sname) } } } .navigationTitle("Stock List") .onAppear { doIfFirst() } } } // This function handles data loading when the app launches for the first time func doIfFirst() { if isNotLoaded { loadDataWithAnimationIfNotLoading() isNotLoaded = false } } // This function ensures data is loaded with an animation and avoids multiple triggers func loadDataWithAnimationIfNotLoading() { if !isLoading { isLoading = true Task { do { try await loadData() } catch { // Capture and store any errors during data loading loadingErrorState = "Data load failed: \(error.localizedDescription)" } isLoading = false } } } // Fetch data from the server and insert it into the SwiftData model context func loadData() async throws { if let blandsOnServer = try await DataModel.shared.getBlands() { for bland in blandsOnServer { // Avoid inserting duplicate keys by checking for existing items in blandList if !blandList.contains(where: { $0.code == bland.code }) { modelContext.insert(bland.bland) } } } } } Entity Definitions: Here are the main entities involved: Bland: @Model class Bland: Identifiable { @Attribute(.unique) var code: String var sname: String @Relationship(deleteRule: .cascade, inverse: \CrossZansu.bland) var zansuList: [CrossZansu] @Relationship(deleteRule: .cascade, inverse: \Trade.bland) var trades: [Trade] } CrossZansu: @Model class CrossZansu: Equatable { @Attribute(.unique) var id: String var bland: Bland? } Trade: @Model class Trade { @Relationship(deleteRule: .nullify) var user: User? var bland: Bland } User: class User { var id: UUID @Relationship(deleteRule: .cascade, inverse: \Trade.user) var trades: [Trade] } Observations: Error Context: The error occurs after the data is fetched and inserted into SwiftData. This suggests an issue with Hashable requirements or duplicate keys being inserted unintentionally. Concurrency Concerns: The fetch and update operations are performed in asynchronous tasks. Could this cause race conditions? Questions: Could this issue be related to how @Relationship and @Attribute(.unique) are managed in SwiftData? What are potential pitfalls with Equatable implementations (e.g., in CrossZansu) when used in SwiftData entities? Are there any recommended approaches for debugging "Duplicate keys" errors in SwiftData? Additional Info: Error Timing: The error occurs only during the app's first launch and consistently within the first minute.
3
1
605
Apr ’25
Container Failing to Initialize After a Successful Migration & Initialization
I'm experiencing the following error with my SwiftData container when running a build: Code=134504 "Cannot use staged migration with an unknown model version." Code Structure - Summary I am using a versionedSchema to store multiple models in SwiftData. I started experiencing this issue when adding two new models in the newest Schema version. Starting from the current public version, V4.4.6, there are two migrations. Migration Summary The first migration is to V4.4.7. This is a lightweight migration removing one attribute from one of the models. This was tested and worked successfully. The second migration is to V5.0.0. This is a custom migration adding two new models, and instantiating instances of the two new models based on data from instances of the existing models. In the initial testing of this version, no issues were observed. Issue and Steps to Reproduce Reproduction of issue: Starting from a fresh build of the publicly released V4.4.6, I run a new build that contains both Schema Versions (V4.4.7 and V5.0.0), and their associated migration stages. This builds successfully, and the container successfully migrates to V5.0.0. Checking the default.store file, all values appear to migrate and instantiate correctly. The second step in reproduction of the issue is to simply stop running the build, and then rebuild, without any code changes. This fails to initialize the model container every time afterwards. Going back to the simulator after successive builds are stopped in Xcode, the app launches and accesses/modifies the model container as normal. Supplementary Issue: I have been putting up with the same, persistent issue in the Xcode Preview Canvas of "Failed to Initialize Model Container" This is a 5 in 6 build issue, where builds will work at random. In the case of previews, I have cleared all data associated with all previews multiple times. The only difference being that the simulator is a 100% failure rate after the initial, successful initialization. I assume this is due to the different build structure of previews. Lastly, of note, the Xcode previews fail at the same line in instantiating the model container as the simulator does. From my research into this issue, people say that the Xcode preview is instantiating from elsewhere. I do have a separate model container set up specifically for canvas previews, but the error does not occur in that container, but rather the app's main container. Possible Contributing Factors & Tested Facts iOS: While I have experienced issues with SwiftData and the complier in iOS 26, I can rule that out as the issue here. This has been tested on simulators running iOS 18.6, 26.0.1, and 26.1, all encountering failures to initialize model container. While in iOS 18, subsequent builds after the successful migration did work, I did eventually encounter the same error and crash. In iOS 26.0.1 and 26.1, these errors come immediately on the second build. Container Initialization for V4.4.6 do { container = try ModelContainer( for: Job.self, JobTask.self, Day.self, Charge.self, Material.self, Person.self, TaskCategory.self, Service.self, migrationPlan: JobifyMigrationPlan.self ) } catch { fatalError("Failed to Initialize Model Container") } Versioned Schema Instance for V4.4.6 (V4.4.7 differs only by versionIdentifier) static var versionIdentifier = Schema.Version(4, 4, 6) static var models: [any PersistentModel.Type] { [Job.self, JobTask.self, Day.self, Charge.self, Material.self, Person.self, TaskCategory.self, Service.self] } Container Initialization for V5.0.0 do { let schema = Schema([Jobify.self, JobTask.self, Day.self, Charge.self, MaterialItem.self, Person.self, TaskCategory.self, Service.self, ServiceJob.self, RecurerRule.self]) container = try ModelContainer( for: schema, migrationPlan: JobifyMigrationPlan.self ) } catch { fatalError("Failed to Initialize Model Container") } Versioned Schema Instance for V5.0.0 static var versionIdentifier = Schema.Version(5, 0, 0) static var models: [any PersistentModel.Type] { [ JobifySchemaV500.Job.self, JobifySchemaV500.JobTask.self, JobifySchemaV500.Day.self, JobifySchemaV500.Charge.self, JobifySchemaV500.Material.self, JobifySchemaV500.Person.self, JobifySchemaV500.TaskCategory.self, JobifySchemaV500.Service.self, JobifySchemaV500.ServiceJob.self, JobifySchemaV500.RecurerRule.self ] } Addressing Differences in Object Names Type-aliasing: All my model types are type-aliased for simplification in view components. All types are aliased as 'JobifySchemeV446.<#Name#>' in V.4.4.6, and 'JobifySchemaV500.<#Name#>' in V5.0.0 Issues with iOS 26: My type-aliases dating back to iOS 17 overlapped with lower level objects in Swift, including 'Job' and 'Material'. These started to be an issue with initializing the model container when running in iOS 26. The type aliases have been renamed since, however the V4.4.6 build with the old names runs and builds perfectly fine in iOS 26 If there is any other code that may be relevant in determining where this error is occurring, I would be happy to add it. My current best theory is simply that I have mistakenly omitted code relevant to the SwiftData Migration.
2
0
569
3w
SwiftUI Sheet view with @Query loses model context
I've run into a strange issue. If a sheet loads a view that has a SwiftData @Query, and there is an if statement in the view body, I get the following error when running an iOS targetted SwiftUI app under MacOS 26.1: Set a .modelContext in view's environment to use Query While the view actually ends up loading the correct data, before it does, it ends up re-creating the sqlite store (opening as /dev/null). The strange thing is that this only happens if there is an if statement in the body. The statement need not ever evaluate true, but it causes the issue. Here's an example. It's based on the default xcode new iOS project w/ SwiftData: struct ContentView: View { @State private var isShowingSheet = false var body: some View { Button(action: { isShowingSheet.toggle() }) { Text("Show Sheet") } .sheet(isPresented: $isShowingSheet, onDismiss: didDismiss) { VStack { ContentSheetView() } } } func didDismiss() { } } struct ContentSheetView: View { @Environment(\.modelContext) private var modelContext @Query public var items: [Item] @State var fault: Bool = false var body: some View { VStack { if fault { Text("Fault!") } Button(action: addItem) { Label("Add Item", systemImage: "plus") } List { ForEach(items) { item in Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) } } } } private func addItem() { withAnimation { let newItem = Item(timestamp: Date()) modelContext.insert(newItem) } } } It requires some data to be added to trigger, but after adding it and dismissing the sheet, opening up the sheet with trigger the Set a .modelContext in view's environment to use Query. Flipping on -com.apple.CoreData.SQLDebug 1 will show it trying to recreate the database. If you remove the if fault { Text("Fault!") } line, it goes away. It also doesn't appear to happen on iPhones or in the iPhone simulator. Explicitly passing modelContext to the ContentSheetView like ContentSheetView().modelContext(modelContext) also seems to fix it. Is this behavior expected?
2
0
174
3w
Error accessing backing data on deleted item in detached task
I have been working on an app for the past few months, and one issue that I have encountered a few times is an error where quick subsequent deletions cause issues with detached tasks that are triggered from some user actions. Inside a Task.detached, I am building an isolated model context, querying for LineItems, then iterating over those items. The crash happens when accessing a Transaction property through a relationship. var byTransactionId: [UUID: [LineItem]] { return Dictionary(grouping: self) { item in item.transaction?.id ?? UUID() } } In this case, the transaction has been deleted, but the relationship existed when the fetch occurred, so the transaction value is non-nil. The crash occurs when accessing the id. This is the error. SwiftData/BackingData.swift:1035: Fatal error: This model instance was invalidated because its backing data could no longer be found the store. PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(backing: SwiftData.PersistentIdentifier.PersistentIdentifierBacking.managedObjectID(0xb43fea2c4bc3b3f5 &lt;x-coredata://A9EFB8E3-CB47-48B2-A7C4-6EEA25D27E2E/Transaction/p1756&gt;))) I see other posts about this error and am exploring some suggestions, but if anyone has any thoughts, they would be appreciated.
2
0
236
3w
SwiftData: This model instance was invalidated because its backing data could no longer be found the store
Hello 👋, I encounter the "This model instance was invalidated because its backing data could no longer be found the store" crash with SwiftData. Which from what I understood means I try to access a model after it has been removed from the store (makes sense). I made a quick sample to reproduce/better understand because there some case(s) I can't figure it out. Let's take a concrete example, we have Home model and a Home can have many Room(s). // Sample code @MainActor let foo = Foo() // A single reference let database = Database(modelContainer: sharedModelContainer) // A single reference @MainActor class Foo { // Properties to explicilty keep reference of model(s) for the purpose of the POC var _homes = [Home]() var _rooms = [Room]() func fetch() async { let homes = await database.fetch().map { sharedModelContainer.mainContext.model(for: $0) as! Home } print(ObjectIdentifier(homes[0]), homes[0].rooms?.map(\.id)) // This will crash here or not. } // Same version of a delete function with subtle changes. // Depending on the one you use calling delete then fetch will result in a crash or not. // Keep a reference to only homes == NO CRASH func deleteV1() async { self._homes = await database.fetch().map { sharedModelContainer.mainContext.model(for: $0) as! Home } await database.delete() } // Keep a reference to only rooms == NO CRASH func deleteV2() async { self._rooms = await database.fetch().map { sharedModelContainer.mainContext.model(for: $0) as! Home }[0].rooms ?? [] await database.delete() } // Keep a reference to homes & rooms == CRASH 💥 func deleteV3() async { self._homes = await database.fetch().map { sharedModelContainer.mainContext.model(for: $0) as! Home } self._rooms = _homes[0].rooms ?? [] // or even only retain reference to rooms that have NOT been deleted 🤔 like here "id: 2" make it crash // self._rooms = _homes[0].rooms?.filter { r in r.id == "2" } ?? [] await database.delete() } } Calling deleteV() then fetch() will result in a crash or not depending on the scenario. I guess I understand deleteV1, deleteV2. In those case an unsaved model is served by the model(for:) API and accessing properties later on will resolve correctly. The doc says: "The identified persistent model, if known to the context; otherwise, an unsaved model with its persistentModelID property set to persistentModelID." But I'm not sure about deleteV3. It seems the ModelContext is kind of "aware" there is still cyclic reference between my models that are retained in my code so it will serve these instances instead when calling model(for:) API ? I see my home still have 4 rooms (instead of 2). So I then try to access rooms that are deleted and it crash. Why of that ? I mean why not returning home with two room like in deleteV1 ? Because SwiftData heavily rely on CoreData may be I miss a very simple thing here. If someone read this and have a clue for me I would be extremely graceful. PS: If someone wants to run it on his machine here's some helpful code: // Database let sharedModelContainer: ModelContainer = { let schema = Schema([ Home.self, Room.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) debugPrint(modelConfiguration.url.absoluteString.replacing("%20", with: "\\ ")) return try! ModelContainer(for: schema, configurations: [modelConfiguration]) }() extension Database { static let shared = Database(modelContainer: sharedModelContainer) } @ModelActor actor Database { func insert() async { let r1 = Room(id: "1", name: "R1") let r2 = Room(id: "2", name: "R2") let r3 = Room(id: "3", name: "R3") let r4 = Room(id: "4", name: "R4") let home = Home(id: "1", name: "My Home") home.rooms = [r1, r2, r3, r4] modelContext.insert(home) try! modelContext.save() } func fetch() async -> [PersistentIdentifier] { try! modelContext.fetchIdentifiers(FetchDescriptor<Home>()) } @MainActor func delete() async { let mainContext = sharedModelContainer.mainContext try! mainContext.delete( model: Room.self, where: #Predicate { r in r.id == "1" || r.id == "4" } ) try! mainContext.save() // 🤔 Calling fetch here seems to solve crash too, force home relationship to be rebuild correctly ? // let _ = try! sharedModelContainer.mainContext.fetch(FetchDescriptor<Home>()) } } // Models @Model class Home: Identifiable { @Attribute(.unique) public var id: String var name: String @Relationship(deleteRule: .cascade, inverse: \Room.home) var rooms: [Room]? init(id: String, name: String, rooms: [Room]? = nil) { self.id = id self.name = name self.rooms = rooms } } @Model class Room: Identifiable { @Attribute(.unique) public var id: String var name: String var home: Home? init(id: String, name: String, home: Home? = nil) { self.id = id self.name = name self.home = home } }
2
0
178
3w
Fetching strategies - Do not fetch redundant data. ETags, Lastmodified, own API? Recommendations, practice?
I am developing an Xcode app with a job feed, with profile view, with chat eg. I fetch using federatet queries to my microservices thru Apollo Router. Infront of the Apollo Router i Have a Kong that adds a X user ID, that the microservices use for personalized feed and other user info. The info is stored with SwiftData. My thought is that i should add a better way of controlling when i need to fetch. I have a “lastupdateAPI” with different entities (profile, profile picture eg). So when nothing has changed we do not fetch. But rather then using a own API for this, isnt ETag better? Or is it any other recommendations with Xcode Swiftui. Good strategies for not fetching what i already have?
2
0
742
Feb ’25
SwiftData Migration: Keeps failing at the end of willMigrate
I've been trying to setup a successful migration, but it keeps failing with this error: NSCloudKitMirroringDelegate are not reusable and should have a lifecycle tied to a given instance of NSPersistentStore. I can't find any information about this online. I added breakpoints throughout the code in willMigrate, and it originally failed on this line: try? context.save() I removed that, and it still failed. After I reload the app, it doesn't run the migration again and the app loads successfully. I figured since it crashed, it would keep trying, but I guess not. Here's how my migration is setup. enum MigrationV1ToV2: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] { [SchemaV1.self, SchemaV2.self] } static var stages: [MigrationStage] { [stage] } static let stage = MigrationStage.custom( fromVersion: SchemaV1.self, toVersion: SchemaV2.self, willMigrate: { context in // Get cycles let cycles = try? context.fetch(FetchDescriptor<SchemaV1.Cycle>()) if let cycles { for cycle in cycles { // Create new recurring objects based on what's in the cycle for income in cycle.income { let recurring = SchemaV2.Recurring(name: income.name, frequency: income.frequency, kind: .income) recurring.addAmount(.init(date: cycle.startDate, amount: income.amount)) context.insert(recurring) } for expense in cycle.expenses { let recurring = SchemaV2.Recurring(name: expense.name, frequency: expense.frequency, kind: .expense) recurring.addAmount(.init(date: cycle.startDate, amount: expense.amount)) context.insert(recurring) } for savings in cycle.savings { let recurring = SchemaV2.Recurring(name: savings.name, frequency: savings.frequency, kind: .savings) recurring.addAmount(.init(date: cycle.startDate, amount: savings.amount)) context.insert(recurring) } for investment in cycle.investments { let recurring = SchemaV2.Recurring(name: investment.name, frequency: investment.frequency, kind: .investment) recurring.addAmount(.init(date: cycle.startDate, amount: investment.amount)) context.insert(recurring) } } //try? context.save() } else { print("The cycles were not able to be fetched.") } }, didMigrate: { context in // Get new recurring objects let newRecurring = try? context.fetch(FetchDescriptor<SchemaV2.Recurring>()) if let newRecurring { for recurring in newRecurring { // Get all recurring with the same name and kind let sameName = newRecurring.filter({ $0.name == recurring.name && $0.kind == recurring.kind }) // Add amount history to recurring object, and then remove matching for match in sameName { recurring.amountHistory.append(contentsOf: match.amountHistory) context.delete(match) } } //try? context.save() } else { print("The new recurring objects could not be fetched.") } } ) } Here's is my modelContainer in the app file. There is a fatal error occurring here that's crashing the app. var sharedModelContainer: ModelContainer = { let schema = Schema(versionedSchema: SchemaV2.self) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer( for: schema, migrationPlan: MigrationV1ToV2.self, configurations: [modelConfiguration] ) } catch { fatalError("Could not create ModelContainer: \(error)") } }() Does anyone have any suggestions for this? EDIT: I found this error in the console that may be relevant. BUG IN CLIENT OF CLOUDKIT: Registering a handler for a CKScheduler activity identifier that has already been registered (com.apple.coredata.cloudkit.activity.export.8F7A1261-4324-40B4-B041-886DF36FBF0A). CloudKit setup failed because it couldn't register a handler for the export activity. There is another instance of this persistent store actively syncing with CloudKit in this process. And here is the fatal error Fatal error: Could not create ModelContainer: SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer, _explanation: nil)
2
3
614
Jan ’25
SwiftData JSONDataStore with relationships
I am trying to add a custom JSON DataStore and DataStoreConfiguration for SwiftData. Apple kindly provided some sample code in the WWDC24 session, "Create a custom data store with SwiftData", and (once updated for API changes since WWDC) that works fine. However, when I try to add a relationship between two classes, it fails. Has anyone successfully made a JSONDataStore with a relationship? Here's my code; firstly the cleaned up code from the WWDC session: import SwiftData final class JSONStoreConfiguration: DataStoreConfiguration { typealias Store = JSONStore var name: String var schema: Schema? var fileURL: URL init(name: String, schema: Schema? = nil, fileURL: URL) { self.name = name self.schema = schema self.fileURL = fileURL } static func == (lhs: JSONStoreConfiguration, rhs: JSONStoreConfiguration) -> Bool { return lhs.name == rhs.name } func hash(into hasher: inout Hasher) { hasher.combine(name) } } final class JSONStore: DataStore { typealias Configuration = JSONStoreConfiguration typealias Snapshot = DefaultSnapshot var configuration: JSONStoreConfiguration var name: String var schema: Schema var identifier: String init(_ configuration: JSONStoreConfiguration, migrationPlan: (any SchemaMigrationPlan.Type)?) throws { self.configuration = configuration self.name = configuration.name self.schema = configuration.schema! self.identifier = configuration.fileURL.lastPathComponent } func save(_ request: DataStoreSaveChangesRequest<DefaultSnapshot>) throws -> DataStoreSaveChangesResult<DefaultSnapshot> { var remappedIdentifiers = [PersistentIdentifier: PersistentIdentifier]() var serializedData = try read() for snapshot in request.inserted { let permanentIdentifier = try PersistentIdentifier.identifier(for: identifier, entityName: snapshot.persistentIdentifier.entityName, primaryKey: UUID()) let permanentSnapshot = snapshot.copy(persistentIdentifier: permanentIdentifier) serializedData[permanentIdentifier] = permanentSnapshot remappedIdentifiers[snapshot.persistentIdentifier] = permanentIdentifier } for snapshot in request.updated { serializedData[snapshot.persistentIdentifier] = snapshot } for snapshot in request.deleted { serializedData[snapshot.persistentIdentifier] = nil } try write(serializedData) return DataStoreSaveChangesResult<DefaultSnapshot>(for: self.identifier, remappedIdentifiers: remappedIdentifiers) } func fetch<T>(_ request: DataStoreFetchRequest<T>) throws -> DataStoreFetchResult<T, DefaultSnapshot> where T : PersistentModel { if request.descriptor.predicate != nil { throw DataStoreError.preferInMemoryFilter } else if request.descriptor.sortBy.count > 0 { throw DataStoreError.preferInMemorySort } let objs = try read() let snapshots = objs.values.map({ $0 }) return DataStoreFetchResult(descriptor: request.descriptor, fetchedSnapshots: snapshots, relatedSnapshots: objs) } func read() throws -> [PersistentIdentifier : DefaultSnapshot] { if FileManager.default.fileExists(atPath: configuration.fileURL.path(percentEncoded: false)) { let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 let data = try decoder.decode([DefaultSnapshot].self, from: try Data(contentsOf: configuration.fileURL)) var result = [PersistentIdentifier: DefaultSnapshot]() data.forEach { s in result[s.persistentIdentifier] = s } return result } else { return [:] } } func write(_ data: [PersistentIdentifier : DefaultSnapshot]) throws { let encoder = JSONEncoder() encoder.dateEncodingStrategy = .iso8601 encoder.outputFormatting = [.prettyPrinted, .sortedKeys] let jsonData = try encoder.encode(data.values.map({ $0 })) try jsonData.write(to: configuration.fileURL) } } The data model classes: import SwiftData @Model class Settings { private(set) var version = 1 @Relationship(deleteRule: .cascade) var hack: Hack? = Hack() init() { } } @Model class Hack { var foo = "Foo" var bar = 42 init() { } } Container: lazy var mainContainer: ModelContainer = { do { let url = // URL to file let configuration = JSONStoreConfiguration(name: "Settings", schema: Schema([Settings.self, Hack.self]), fileURL: url) return try ModelContainer(for: Settings.self, Hack.self, configurations: configuration) } catch { fatalError("Container error: \(error.localizedDescription)") } }() Load function, that saves a new Settings JSON file if there isn't an existing one: @MainActor func loadSettings() { let mainContext = mainContainer.mainContext let descriptor = FetchDescriptor<Settings>() let settingsArray = try? mainContext.fetch(descriptor) print("\(settingsArray?.count ?? 0) settings found") if let settingsArray, let settings = settingsArray.last { print("Loaded") } else { let settings = Settings() mainContext.insert(settings) do { try mainContext.save() } catch { print("Error saving settings: \(error)") } } } The save operation creates a JSON file, which while it isn't a format I would choose, is acceptable, though I notice that the "hack" property (the relationship) doesn't have the correct identifier. When I run the app again to load the data, I get an error (that there wasn't room to include in this post). Even if I change Apple's code to not assign a new identifier, so the relationship property and its pointee have the same identifier, it still doesn't load. Am I doing something obviously wrong, or are relationships not supported in custom data stores?
2
0
717
Apr ’25
SwiftData crashes after updating to MacOS 15.2
After updating to 15.2 I am seeing frequent crashes in my in-development app related to SwiftData. For instance, I have a 100% reproducible crash when I make the app lose and regain focus. There is also a crash that seem to be triggered by a modelContext.save() call in one of my ModelActors. With both of these crashes, the issue seems to be around keeping SwiftData models up to date. The first item in the stacktrace that is not machinecode is always some getter on a SwiftData collection or object. In the console, these crashes are accompanied by output along the lines of: === AttributeGraph: cycle detected through attribute 820680 === precondition failure: setting value during update: 930592 error: the replacement path doesn't exist: "/var/folders/b7/0dw7ztp13fgfxlj19by851tw0000gn/T/swift-generated-sources/@__swiftmacro_10SpaceDebug8TodoListV5todos33_5575DE008494C519BB9FA49C405133E1LL5QueryfMa_.swift" error: the replacement path doesn't exist: "/var/folders/b7/0dw7ztp13fgfxlj19by851tw0000gn/T/swift-generated-sources/@__swiftmacro_10SpaceDebug8TodoListV5todos33_5575DE008494C519BB9FA49C405133E1LL5QueryfMa_.swift" Can't show file for stack frame : <DBGLLDBStackFrame: 0x35a57c4e0> - stackNumber:27 - name:TodoList.todos.getter. The file path does not exist on the file system: /var/folders/b7/0dw7ztp13fgfxlj19by851tw0000gn/T/swift-generated-sources/@__swiftmacro_10SpaceDebug8TodoListV5todos33_5575DE008494C519BB9FA49C405133E1LL5QueryfMa_.swiftCan't show file for stack frame : <DBGLLDBStackFrame: 0x35a57c4e0> - stackNumber:27 - name:TodoList.todos.getter. The file path does not exist on the file system: /var/folders/b7/0dw7ztp13fgfxlj19by851tw0000gn/T/swift-generated-sources/@__swiftmacro_10SpaceDebug8TodoListV5todos33_5575DE008494C519BB9FA49C405133E1LL5QueryfMa_.swiftCan't show file for stack frame : <DBGLLDBStackFrame: 0x35a5a82f0> - stackNumber:62 - name:TodoList.todos.getter. The file path does not exist on the file system: /var/folders/b7/0dw7ztp13fgfxlj19by851tw0000gn/T/swift-generated-sources/@__swiftmacro_10SpaceDebug8TodoListV5todos33_5575DE008494C519BB9FA49C405133E1LL5QueryfMa_.swift Has anyone run into something similar? I'm looking for suggestions on how to debug this. Cheers, Bastiaan
2
0
617
Jan ’25
How is Record Zone Sharing done?
My use case is the following: Every user of my app can create as an owner a set of items.  These items are private until the owner invites other users to share all of them as participant. The participants can modify the shared items and/or add other items. So, sharing is not done related to individual items, but to all items of an owner. I want to use CoreData & CloudKit to have local copies of private and shared items. To my understanding, CoreData & CloudKit puts all mirrored items in a special zone „com.apple.coredata.cloudkit.zone“. So, this zone should be shared, i.e. all items in it. In the video it is said that NSPersistentCloudKitContainer uses Record Zone Sharing optionally in contrast to hierarchically record sharing using a root record. But how is this done? Maybe I can declare zone „com.apple.coredata.cloudkit.zone“ as a shared zone?
2
0
994
Apr ’25
SwiftData and iCloud
I'm a first time developer for Swift, (getting on a bit!) but after programming in VB back in the late 90s I wanted to write an app for iPhone. I think I might have gone about it the wrong way, but I've got an app that works great on my iPhone or works great on my iPad. It saves the data persistently on device, but, no matter how much I try, what I read and even resorting to AI (ChatGPT & Gemini) I still can't get it to save the data on iCloud to synchronise between the two and work across the devices. I think it must be something pretty fundamental I'm doing (or more likely not doing) that is causing the issue. I'm setting up my signing and capabilities as per the available instructions but I always get a fatal error. I think it might be something to do with making fields optional, but at this point I'm second guessing myself and feeling a complete failure. Any advice or pointers would be really gratefully appreciated. I like my app and would like eventually to get it on the App Store but at this point in time I feel it should be on the failed projects heap! I've even tried a new Xcode project for iOS and asking it to use SwiftData and CloudKit - the default project should work - right? But it absolutely doesn't for me. Please send help!!
2
0
165
Apr ’25
CoreData crashing on iOS26
Hi, I work on a financial app in Brazil and since Beta 1 we're getting several crashes. We already opened a code level support and a few feedback issues, but haven't got any updates on that yet. We were able to resolve some crashes changing some of our implementation but we aren't able to understand what might be happening with this last one. This is the log we got on console: erro 11:55:41.805875-0300 MyApp CoreData: error: Failed to load NSManagedObjectModel with URL 'file:///private/var/containers/Bundle/Application/0B9F47D9-9B83-4CFF-8202-3718097C92AE/MyApp.app/ServerDrivenModel.momd/' We double checked and the momd is inside the bundle. The same app works on any other iOS version and if we build using Xcode directly (without archiving and installing on an iOS26 device) it works as expected. Have anyone else faced a similar error? Any tips or advice on how we can try to solve that?
2
2
184
Jul ’25
CKSyncEngine keeps attempting to sync the same record
I am attempting to migrate a cloudkit module that calls on manual cloudkit methods for fetching record zone changes, modifying records, etc to one that utilizes CKSyncEngine. I've got a basic implementation working with just a create method for one of my data models, however it seems like the sync engine keeps calling sync events on the same pending changes. Here is my current flow: The user will hit some button that lets them fill out a form to create a data model. The user saves the form. This triggers a method that takes the resulting data model and queues it to the sync engine's state (engine.state.add(pendingRecordZoneChanges: pendingChanges) I have my delegate method nextRecordZoneChangeBatch(_ context:...) implemented where it fetches the corresponding data model using the record ID and returns a batch containing the corresponding populated record from the data model. I have the handleEvent(_ event:...) delegate method implemented where I handle both .fetchRecordZoneChanges and .sentRecordZoneChanges. I have set up .sentRecordZoneChanges to merge the server record into my local record (and persisted locally) so that the record change tags are the same. After this last portion, it seems that the sync engine continues to keep pushing syncs/updates and I end up with numerous handleEvent(_ event:) calls that keep returning savedRecords (and occasionally failedRecordSaves). Am I missing some step to remove the record from the changes after the sync engine recognizes that I have properly saved the record to the server?
2
0
424
Jan ’25