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

Is there a guaranteed order for records in CKSyncEngine's handleFetchedRecordZoneChanges?
I have two recordTypes in CloudKit: Author and Book. The Book records have their parent property set to an Author, enabling hierarchical record sharing (i.e., if an Author record is shared, the participant can see all books associated with that author in their shared database). When syncing with CKSyncEngine, I was expecting handleFetchedRecordZoneChanges to deliver all Author records before their associated Book records. However, unless I’m missing something, the order appears to be random. This randomness forces me to handle two codepaths in my app (opposed to just one) to replicate CloudKit references in my local persistency storage: Book arrives before its Author → I store the Book but defer setting its parent reference until the corresponding Author arrives. Author arrives before its Books → I can immediately set the parent reference when each Book arrives. Is there a way to ensure that Author records always arrive before Book records when syncing with CKSyncEngine? Or is this behavior inherently unordered and I have to implement two codepaths?
1
0
633
Feb ’25
Invalid bundle ID for container
Hi. I am having this error when trying to write to CloudKit public database. <CKError 0x600000dbc4e0: "Permission Failure" (10/2007); server message = "Invalid bundle ID for container"; On app launch, I check for account status and ensure that the correct bundle identifier and container is being used. When the account status is checked, I do get the correct bundle id and container id printed in the console but trying to read or write to the container would throw that "Invalid bundle ID for container" error. private init() { container = CKContainer.default() publicDB = container.publicCloudDatabase // Check iCloud account status checkAccountStatus() } func checkAccountStatus() { print("🔍 CloudKit Debug:") print("🔍 Bundle identifier from app: (Bundle.main.bundleIdentifier ?? "unknown")") print("🔍 Container identifier: (container.containerIdentifier ?? "unknown")") container.accountStatus { [weak self] status, error in DispatchQueue.main.async { switch status { case .available: self?.isSignedIn = true self?.fetchUserID() case .noAccount, .restricted, .couldNotDetermine: self?.isSignedIn = false self?.errorMessage = "Please sign in to iCloud in Settings to use this app." default: self?.isSignedIn = false self?.errorMessage = "Unknown iCloud account status." } print("User is signed into iCloud: \(self?.isSignedIn ?? false)") print("Account status: \(status.rawValue)") } } } I have tried: Creating a new container Unselecting and selecting the container in signing & capabilities Unselecting and selecting the container in App ID Configuration I used to have swift data models in my code and read that swift data is not compatible with CloudKit public data so I removed all the models and any swift data codes and only uses CloudKit public database. let savedRecord = try await publicDB.save(record) Nothing seems to work. If anyone could help please? Rgds, Hans
1
0
206
Jun ’25
ForEach and RandomAccessCollection
I'm trying to build a custom FetchRequest that I can use outside a View. I've built the following ObservableFetchRequest class based on this article: https://augmentedcode.io/2023/04/03/nsfetchedresultscontroller-wrapper-for-swiftui-view-models @Observable @MainActor class ObservableFetchRequest&lt;Result: Storable&gt;: NSObject, @preconcurrency NSFetchedResultsControllerDelegate { private let controller: NSFetchedResultsController&lt;Result.E&gt; private var results: [Result] = [] init(context: NSManagedObjectContext = .default, predicate: NSPredicate? = Result.E.defaultPredicate(), sortDescriptors: [NSSortDescriptor] = Result.E.sortDescripors) { guard let request = Result.E.fetchRequest() as? NSFetchRequest&lt;Result.E&gt; else { fatalError("Failed to create fetch request for \(Result.self)") } request.predicate = predicate request.sortDescriptors = sortDescriptors controller = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil) super.init() controller.delegate = self fetch() } private func fetch() { do { try controller.performFetch() refresh() } catch { fatalError("Failed to fetch results for \(Result.self)") } } private func refresh() { results = controller.fetchedObjects?.map { Result($0) } ?? [] } var predicate: NSPredicate? { get { controller.fetchRequest.predicate } set { controller.fetchRequest.predicate = newValue fetch() } } var sortDescriptors: [NSSortDescriptor] { get { controller.fetchRequest.sortDescriptors ?? [] } set { controller.fetchRequest.sortDescriptors = newValue.isEmpty ? nil : newValue fetch() } } internal func controllerDidChangeContent(_ controller: NSFetchedResultsController&lt;any NSFetchRequestResult&gt;) { refresh() } } Till this point, everything works fine. Then, I conformed my class to RandomAccessCollection, so I could use in a ForEach loop without having to access the results property. extension ObservableFetchRequest: @preconcurrency RandomAccessCollection, @preconcurrency MutableCollection { subscript(position: Index) -&gt; Result { get { results[position] } set { results[position] = newValue } } public var endIndex: Index { results.endIndex } public var indices: Indices { results.indices } public var startIndex: Index { results.startIndex } public func distance(from start: Index, to end: Index) -&gt; Int { results.distance(from: start, to: end) } public func index(_ i: Index, offsetBy distance: Int) -&gt; Index { results.index(i, offsetBy: distance) } public func index(_ i: Index, offsetBy distance: Int, limitedBy limit: Index) -&gt; Index? { results.index(i, offsetBy: distance, limitedBy: limit) } public func index(after i: Index) -&gt; Index { results.index(after: i) } public func index(before i: Index) -&gt; Index { results.index(before: i) } public typealias Element = Result public typealias Index = Int } The issue is, when I update the ObservableFetchRequest predicate while searching, it causes a Index out of range error in the Collection subscript because the ForEach loop (or a List loop) access a old version of the array when the item property is optional. List(request, selection: $selection) { item in VStack(alignment: .leading) { Text(item.content) if let information = item.information { // here's the issue, if I leave this out, everything works Text(information) .font(.callout) .foregroundStyle(.secondary) } } .tag(item.id) .contextMenu { if Item.self is Client.Type { Button("Editar") { openWindow(ClientView(client: item as! Client), id: item.id!) } } } } Is it some RandomAccessCollection issue or a SwiftUI bug?
0
0
136
May ’25
Unable to see data from a production environment
I am trying to test using Testflight and have set up a test with a user on an account I also own which is different to me developer account. The app I believe is running in production on a separate device and is working from a user point of view, however I am not able to query the data via the console. As I said I know the user id and password as tey are mine so even when I use the Act as user service it logs in but the query is empty. I'm assuming I'm not doing anything wrong its possibly an security issue that is preventing me accessing this account. My question to the group then is how do I verify the data that is being tested?
1
0
622
Feb ’25
Using Observation class for multiple SwiftData Models
Greetings i have an app that uses three different SwiftData models and i want to know what is the best way to use the them accross the app. I though a centralized behaviour and i want to know if it a correct approach.First let's suppose that the first view of the app will load the three models using the @Enviroment that work with @Observation. Then to other views that add data to the swiftModels again with the @Environment. Another View that will use the swiftData models with graph and datas for average and min and max.Is this a corrent way? or i should use @Query in every view that i want and ModelContext when i add the data. @Observable class CentralizedDataModels { var firstDataModel: [FirstDataModel] = [] var secondDataModel: [SecondDataModel] = [] var thirdDataModel: [ThirdDataModel] = [] let context: ModelContext init(context:ModelContext) { self.context = context } }
0
0
122
Jun ’25
How to distinguish which operations in the file provider are during offline period
Currently tested, if the file provider goes offline (referring to calling disconnect) and deletes a file, the system will automatically trigger the deleteItems event after reconnecting (note that only after calling reconnect again will the current deleteItems logic be reached). However, for offline deletion, I would like to pass it directly without operating on the cloud. Can mounting disks determine which operations were performed offline during reboot
1
0
66
1w
SwiftData property marked ephemeral getting persisted in CloudKit
Am I misunderstanding the expected behavior here, or is there a bug in the behavior of @Attribute(.ephemeral) tagged SwiftData model properties? The documentation for .ephemeral says "Track changes to this property but do not persist". I started using .ephemeral because @Transient was inhibiting SwiftUI from reacting to changes to the property through @Observable. I am updating the value of my @Attribute(.ephemeral) property about once a second and I am seeing corresponding console log output showing the property as part of the generated CKRecord object. I then confirmed in the CloudKit dev portal that the .ephemeral property was added to the Record schema and contains real values. The behavior seems as though the .ephemeral property is being completely ignored. This is observed in a new Xcode project using SwiftData with CloudKit, Xcode 16.2, macOS 15.3.1 and during Build & Run testing on physical devices.
1
0
703
Feb ’25
defaultIsolation option and Core Data
When creating a new project in Xcode 26, the default for defaultIsolation is MainActor. Core Data creates classes for each entity using code gen, but now those classes are also internally marked as MainActor, which causes issues when accessing managed object from a background thread like this. Is there a way to fix this warning or should Xcode actually mark these auto generated classes as nonisolated to make this better? Filed as FB13840800. nonisolated struct BackgroundDataHandler { @concurrent func saveItem() async throws { let context = await PersistenceController.shared.container.newBackgroundContext() try await context.perform { let newGame = Item(context: context) newGame.timestamp = Date.now // Main actor-isolated property 'timestamp' can not be mutated from a nonisolated context; this is an error in the Swift 6 language mode try context.save() } } } Turning code gen off inside the model and creating it manually, with the nonisolated keyword, gets rid of the warning and still works fine. So I guess the auto generated class could adopt this as well? public import Foundation public import CoreData public typealias ItemCoreDataClassSet = NSSet @objc(Item) nonisolated public class Item: NSManagedObject { }
1
0
98
Jun ’25
SwiftData Background Fetching?
Hi, I am experiencing main thread freezes from fetching on Main Actor. Attempting to move the function to a background thread, but whenever I reference the TestModel in a nonisolated context or in another model actor, I get this warning: Main actor-isolated conformance of 'TestModel' to 'PersistentModel' cannot be used in actor-isolated context; this is an error in the Swift 6 language mode Is there a way to do this correctly? Recreation, warning on line 13: class TestModel { var property: Bool = true init() {} } struct SendableTestModel: Sendable { let property: Bool } @ModelActor actor BackgroundActor { func fetch() throws -> [SendableTestModel] { try modelContext.fetch(FetchDescriptor<TestModel>()).map { SendableTestModel(property: $0.property) } } }
1
0
135
Jul ’25
SwiftData with CloudKit Sync Issue
I am using SwiftData with CloudKit to synchronize data across multiple devices, and I have encountered an issue: occasionally, abnormal sync behavior occurs between two devices (it does not happen 100% of the time—only some users have reported this problem). It seems as if synchronization between the two devices completely stops; no matter what operations are performed on one end, the other end shows no response. After investigating, I suspect the issue might be caused by both devices simultaneously modifying the same field, which could lead to CloudKit's logic being unable to handle such conflicts and causing the sync to stall. Are there any methods to avoid or resolve this situation? Of course, I’m not entirely sure if this is the root cause. Has anyone encountered a similar issue?
1
0
129
11h
A crash occurs when fetching history when Model has preserveValueOnDeletion attribute and using inheritance
Hello, In our app, we’ve modeled our schema using inheritance introduced in iOS 26.0, and we’re implementing SwiftData History to re-fetch models only when necessary. @Model public class Transaction { @Attribute(.preserveValueOnDeletion) public var date: Date = Date() public var amount: Double = 0 public var memo: String? } @Model public final class Spending: Transaction { public var installmentIndex: Int = 1 public var installment: Int = 1 public var installmentID: UUID? } If data has been deleted from database, we need to check a date property to determine whether to re-fetch datas. To do this, we added the preserveValueOnDeletion attribute to date property so we could retrieve it from the History tombstone value. However, after adding this attribute, a crash occurs. There is a console log Could not cast value of type 'Swift.ReferenceWritableKeyPath<Shared.ModelSchemaV5.Transaction, Foundation.Date>' (0x106bf8328) to 'Swift.PartialKeyPath<Shared.ModelSchemaV5.Spending>' (0x1094f21d8). and error log attached StrictMoneyChecking-2025-11-07-105108.txt I also tried this in the recent SampleTrip app, and fetching all history after a deletion causes the same crash. Is this issue currently being worked on or under investigation?
1
0
262
Nov ’25
Xcode 26.1 / OS 26.1 regression with schema and macros
After Xcode 26.1 was updated and installing the OS 26.1 simulators, my app started crashing related to transformable properties. When I checked my schema, I noticed that properties with array collection types are suddenly set with an option transformable with Optional("NSSecureUnarchiveFromData")], even though I do not use any transformable types. I verified the macros, no transformable was specified. This is causing ModelCoders to encode/decode my properties incorrectly. This is not an issue when I switch back to OS 26.0 simulators.
4
0
272
Nov ’25
SwiftData: Unexpected backing data for snapshot creation
When deleting a SwiftData entity, I sometimes encounter the following error in a document based SwiftUI app: Fatal error: Unexpected backing data for snapshot creation: SwiftData._FullFutureBackingData<MyEntityClass> The deletion happens in a SwiftUI View and the code used to retrieve the entity is standard (the ModelContext is injected from the @Environment): let myEntity = modelContext.model(for: entityIdToDelete) modelContext.delete(myEntity) Unfortunately, I haven't yet managed to isolate this any further in order to come up with a reproducible PoC. Could you give me further information about what this error means?
3
0
226
Oct ’25
SwiftData Migration: Objects Created in Custom Migration Aren't Persisted or Queryable
Description: I'm experiencing a critical issue with SwiftData custom migrations where objects created during migration appear to be inserted successfully but aren't persisted or found by queries after migration completes. The migration logs show objects being created, but subsequent queries return zero results. Problem Details: I'm migrating from schema version V2 to V3, which involves: Renaming Person class to GroupData Keeping the same data structure but changing the class name Using a custom migration stage to copy data from old to new schema Migration Code: swift static let migrationV2toV3 = MigrationStage.custom( fromVersion: LinkMapV2.self, toVersion: LinkMapV3.self, willMigrate: { context in do { let persons = try context.fetch(FetchDescriptor<LinkMapV2.Person>()) print("Found (persons.count) Person objects to migrate") // ✅ Shows 11 objects for person in persons { let newGroup = LinkMapV3.GroupData( id: person.id, // Same UUID name: person.name, // ... other properties ) context.insert(newGroup) print("Inserted GroupData: '\(newGroup.name)'") // ✅ Confirms insertion } try context.save() // ✅ No error thrown print("Successfully migrated \(persons.count) objects") // ✅ Confirms save } catch { print("Migration error: \(error)") } }, didMigrate: { context in do { let groups = try context.fetch(FetchDescriptor<LinkMapV3.GroupData>()) print("Final GroupData count: \(groups.count)") // ❌ Shows 0 objects! } catch { print("Verification error: \(error)") } } ) Console Output: text === MIGRATION STARTED === Found 11 Person objects to migrate Migrating Person: 'Riverside of pipewall' with ID: 7A08C633-4467-4F52-AF0B-579545BA88D0 Inserted new GroupData: 'Riverside of pipewall' ... (all 11 objects processed) ... === MIGRATION COMPLETED === Successfully migrated 11 Person objects to GroupData === MIGRATION VERIFICATION === New GroupData count: 0 // ❌ PROBLEM: No objects found! What I've Tried: Multiple context approaches: Using the provided migration context Creating a new background context with ModelContext(context.container) Using context.performAndWait for thread safety Different save strategies: Calling try context.save() after insertions Letting SwiftData handle saving automatically Multiple save calls at different points Verification methods: Checking in didMigrate closure Checking in app's ContentView after migration completes Using both @Query and manual FetchDescriptor Schema variations: Direct V2→V3 migration Intermediate V2.5 schema with both classes Lightweight migration with @Attribute(originalName:) Current Behavior: Migration runs without errors Objects appear to be inserted successfully context.save() completes without throwing errors But queries in didMigrate and post-migration return empty results The objects seem to exist in a temporary state that doesn't persist Expected Behavior: Objects created during migration should be persisted and queryable Post-migration queries should return the migrated objects Data should be available in the main app after migration completes Environment: Xcode 16.0+ iOS 18.0+ SwiftData Swift 6.0+ Key Questions: Is there a specific way migration contexts should be handled for data to persist? Are there known issues with object persistence in custom migrations? Should we be using a different approach for class renaming migrations? Is there a way to verify that objects are actually being written to the persistent store? The migration appears to work perfectly until the verification step, where all created objects seem to vanish. Any guidance would be greatly appreciated! Additional Context from my investigation: I've noticed these warning messages during migration that might be relevant: text SwiftData.ModelContext: Unbinding from the main queue. This context was instantiated on the main queue but is being used off it. error: Persistent History (76) has to be truncated due to the following entities being removed: (Person) This suggests there might be threading or context lifecycle issues affecting persistence. Let me know if you need any additional information about my setup or migration configuration!
1
0
93
Nov ’25
CloudKit with Unreal Engine
Hi everyone, Im trying to set up CloudKit for my Unreal Engine 5.4 project but seem to be hitting some roadblocks on how to set up the Record Types. From my understanding I need to set up a "file" record type with a "contents" asset field - but even with this it doesn't seem to work :( Any unreal engine devs with some experience on this who could help me out? Thanks!
0
0
113
Sep ’25
'NSInvalidArgumentException', reason: 'Duplicate version checksums across stages detected.'
I have an iOS app using SwiftData with VersionedSchema. The schema is synchronized with an CloudKit container. I previously introduced some model properties that I have now removed, as they are no longer needed. This results in the current schema version being identical to one of the previous ones (except for its version number). This results in the following exception: 'NSInvalidArgumentException', reason: 'Duplicate version checksums across stages detected.' So it looks like we cannot have a newer schema version with an identical content to an older schema version. The intuitive way would be to re-add the old (identical) schema version to the end of the "schemas" list property in the SchemaMigrationPlan, in order to signal that it is the newest one, and to add a migration stage back to it, thus: public enum MySchemaMigrationPlan: SchemaMigrationPlan { public static var schemas: [any VersionedSchema.Type] { [ SchemaV100.self, SchemaV101.self, SchemaV100.self ] } public static var stages: [MigrationStage] { [ migrateV100toV101, migrateV101toV100 ] } However, I am not sure if this is the right way to go, as previously, as I wanted to write unit tests for schema migration and rollback, I tried defining an inverse for each migration stage, so that I could trigger a migration and a rollback from a unit test, which resulted in an exception saying that it is not supported to downgrade a VersionedSchema. I must admit that I solved the original problem by introducing a dummy model property that I will later remove. What would have been the correct approach?
1
0
118
Jun ’25
SwiftData 100% crash when fetching history with codable (test included!)
SwiftData crashes 100% when fetching history of a model that contains an optional codable property that's updated: SwiftData/Schema.swift:389: Fatal error: Failed to materialize a keypath for someCodableID.someID from CrashModel. It is possible that this path traverses a type that does not work with append(), please file a bug report with a test. Would really appreciate some help or even a workaround. Code: import Foundation import SwiftData import Testing struct VaultsSwiftDataKnownIssuesTests { @Test func testCodableCrashInHistoryFetch() async throws { let container = try ModelContainer( for: CrashModel.self, configurations: .init( isStoredInMemoryOnly: true ) ) let context = ModelContext(container) try SimpleHistoryChecker.hasLocalHistoryChanges(context: context) // 1: insert a new value and save let model = CrashModel() model.someCodableID = SomeCodableID(someID: "testid1") context.insert(model) try context.save() // 2: check history it's fine. try SimpleHistoryChecker.hasLocalHistoryChanges(context: context) // 3: update the inserted value before then save model.someCodableID = SomeCodableID(someID: "testid2") try context.save() // The next check will always crash on fetchHistory with this error: /* SwiftData/Schema.swift:389: Fatal error: Failed to materialize a keypath for someCodableID.someID from CrashModel. It is possible that this path traverses a type that does not work with append(), please file a bug report with a test. */ try SimpleHistoryChecker.hasLocalHistoryChanges(context: context) } } @Model final class CrashModel { // optional codable crashes. var someCodableID: SomeCodableID? // these actually work: //var someCodableID: SomeCodableID //var someCodableID: [SomeCodableID] init() {} } public struct SomeCodableID: Codable { public let someID: String } final class SimpleHistoryChecker { static func hasLocalHistoryChanges(context: ModelContext) throws { let descriptor = HistoryDescriptor<DefaultHistoryTransaction>() let history = try context.fetchHistory(descriptor) guard let last = history.last else { return } print(last) } }
0
0
88
May ’25
CKShare Fails with quotaExceeded Error on Family iCloud Plan
Hello, When attempting to create a CKShare on a personal device linked to a Family iCloud plan (non-primary account holder), the operation fails with a quotaExceeded error. This occurs with the Family plan having 1.5TB available storage space. This is also causing a data loss for the object(s) that were attempted to be shared. Details Account Type: Family iCloud Plan (2TB total storage) Current Family Usage: 399GB iCloud Account Usage: 70 GB Steps to Reproduce: Have an iCloud account with storage over the 5GB free space limit. Be on a part of a iCloud Family Plan as the non-primary account holder. Have storage space available in the Family Plan Attempt to start a CloudKit Share/Collaboration on the device. Observe that the CKShare creation fails with a quotaExceeded error. Expected Behavior: The CKShare should be successfully created, reflecting the total available storage of the Family plan. Observed Behavior: The CKShare fails to be created with quotaExceeded. Additional Testing On a test device using an iCloud account with no stored data, the CKShare was created successfully and shared without issue. Suspected Cause The CKShare functionality is verifying the personal storage allocation of the iCloud account and failing without checking total available storage provided by the Family plan.
2
0
766
Jan ’25
Data Transfer or Upload to Cloudkit in Published Mode
So i created an App and for some time it was working fine. The app has features to show pdf to users without logging in. I needed to upload all data to cloudkit on public database. I was not having knowledge that there are 2 mode being a noob in coding so after i saved all records in development mode in cloudkit when i published my app, i was not able to see them (Reason because live mode works in Production mode). So i need help now to transfer data from development mode to production mode or any app or code that can help me upload all data in production mode.
1
0
113
Mar ’25
How to Delete Tips from CloudKit?
Hi! I use Tips with CloudKit and it works very well, however when a user want to remove their data from CloudKit, how to do that? In CoreData with CloudKit area, NSPersistentCloudKitContainer have purgeObjectsAndRecordsInZone to delete both local managed objects and CloudKit records, however there is no information about the TipKit deletion. Does anyone know ideas?
2
0
431
Mar ’25