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

How to provide visual feedback about iCloud sync status when the user reinstalls an app?
It takes a few seconds, sometimes a few minutes for records to be downloaded back from CloudKit when the user reinstalls the app, which leads users to thinking their data was lost. I would like to know if there’s any way to provide a visual feedback about the current CloudKit sync status so I can let users know their data is being in fact downloaded back to their devices.
2
0
191
Mar ’25
Debugging/Fixing deleted relationship objects with SwiftData
Using SwiftData and this is the simplest example I could boil down: @Model final class Item { var timestamp: Date var tag: Tag? init(timestamp: Date) { self.timestamp = timestamp } } @Model final class Tag { var timestamp: Date init(timestamp: Date) { self.timestamp = timestamp } } Notice Tag has no reference to Item. So if I create a bunch of items and set their Tag. Later on I add the ability to delete a Tag. Since I haven't added inverse relationship Item now references a tag that no longer exists so so I get these types of errors: SwiftData/BackingData.swift:875: Fatal error: This model instance was invalidated because its backing data could no longer be found the store. PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://EEC1D410-F87E-4F1F-B82D-8F2153A0B23C/Tag/p1), implementation: SwiftData.PersistentIdentifierImplementation) I think I understand now that I just need to add the item reference to Tag and SwiftData will nullify all Item references to that tag when a Tag is deleted. But, the damage is already done. How can I iterate through all Items that referenced a deleted tag and set them to nil or to a placeholder Tag? Or how can I catch that error and fix it when it comes up? The crash doesn't occur when loading an Item, only when accessing item.tag?.timestamp, in fact, item.tag?.id is still ok and doesn't crash since it doesn't have to load the backing data. I've tried things like just looping through all items and setting tag to nil, but saving the model context fails because somewhere in there it still tries to validate the old value. Thanks!
2
0
298
Mar ’25
Sync an interactive widget's Core Data store with the main app (and iCloud)
Hi everyone! I have an app on the App Store that uses Core Data as its data store. (It's called Count on Me: Tally Counter. Feel free to check it out.) One of the app's core feature is an interactive widget with a simple button. When the button is tapped, it's supposed to update the entity in the store. My requirement is that the changes are then reflected with minimal latency in the main app and – ideally – also on other devices of the same iCloud user. And vice-versa: When an entity is updated in the app (or on another device where the same iCloud user is logged in), the widget that shows this entity should also refresh to reflect the changes. I have read multiple articles, downloaded sample projects, searched Stackoverflow and the Apple developer forums, and tried to squeeze a solution out of AI, but couldn't figure out how to make this work reliably. So I tried to reduce the core problem to a minimal example project. It has two issues that I cannot resolve: When I update an entity in the app, the widget is immediately updated as intended (due to a call to WidgetCenter's reloadAllTimelines method). However, when I update the same entity from the interactive widget using the same app intent, the changes are not reflected in the main app. For the widget and the app to use the same local data store, I need to enable App Groups in both targets and set a custom location for the store within the shared app group. So I specify a custom URL for the NSPersistentStoreDescription when setting up the Core Data stack. The moment I do this, iCloud sync breaks. Issue no. 1 is far more important to me as I haven't officially enabled iCloud sync yet in my real app that's already on the App Store. But it would be wonderful to resolve issue no. 2 as well. Surely, there must be a way to synchronize changes to the source of truth triggered by interactive widget with other devices of the same iCloud user. Otherwise, the feature to talk to the main app and the feature to synchronize with iCloud would be mutually exclusive. Some other developers I talked to have suggested that the widget should only communicate proposed changes to the main app and once the main app is opened, it processes these changes and writes them to the NSPersistentCloudKitContainer which then synchronizes across devices. This is not an option for me as it would result in a stale state and potential data conflicts with different devices. For example, when a user has the same widget on their iPhone and their iPad, taps a button on the iPhone widget, that change would not be reflected on the iPad widget until the user decides to open the app on the iPhone. At the same time, the user could tap the button multiple times on their iPad widget, resulting in a conflicting state on both devices. Thus, this approach is not a viable solution. An answer to this question will be greatly appreciated. The whole code including the setup of the Core Data stack is included in the repository reference above. Thank you!
4
0
277
Mar ’25
custom share workflow
I am working on a software where we want to add the feature to share the whole database with the other user. Database is iCloud combined with coredata. The other user(s) should be able to edit /delete and even create new objects in the share. I did this with this code witch directly from sample code let participants = try await ckConainer.fetchParticipants(matching: [lookupInfo], into: selectedStore) for participant in participants { participant.permission = .readWrite participant.role = .privateUser share.addParticipant(participant) } try await ckConainer.persistUpdatedShare(share, in: selectedStore) the other user gets invited and I can see this in iCloud database that the other user is invited with status invited. but the other user never gets a mail or something to accept and join the share. How does the other needs to accept the invitation ?
2
0
243
Mar ’25
CloudKit keyvalue pair debug ?
Hello ! I am using this iCloud key value pair mechanism to save small app configuration between iOS and tvOS. I would say it is working. But when I go back and forth between debug and release (TestFlight) modes, it is like both apps are not connected anymore. I spend a lot of time restarting all devices, rebuilding, activating / deactivating iCloud capabilities in the Xcode project. It is like the app is mixing debug and release data. Is there an easy way to check what is happening exactly ? I know there's nothing on CloudKit console, so .... Thank you Frederic
3
0
314
Mar ’25
Can personal information be taken from creatorUserRecordID in a CKrecord?
I am using cloudkit to save users high scores in a public database. The preference over using Game Center is because of simplicity and works really well for what I want to achieve. I simply want to let users know their global position. Because of data privacy laws the app asks the user for their permission to submit their score each time they get a new high score. However, I have noticed that CKRecords under 'created' and 'modified' in addition to UTC time and date also contain creatorUserRecordID. Could this be a privacy issue? Can you extract any personal information from this? Can this be used to track back to the user? Is it linked to CKUserIdentity which I understand does contain personal information, although as I understand you need users consent to get this information. Under creatorUserRecordID it says... "Every user of the app has a unique user record that is empty by default. Apps can add data to the user record on behalf of the user, but don’t store sensitive data in it" Currently I simply ask the user if they are happy to submit their score. But do I need to point out that it also stores a creatorUserRecordID? Obviously I don't want to do this if it is not needed as the user will 1) Probably not understand what a creatorUserRecordID is and 2) It makes the question complicated and will likely make most people refuse to submit their score. If it is a privacy issue, is there anyway to stop a CKRecord creating this ID and simply save a score? All I need is a list of scores so the app can determine their current position. If creatorUserRecordID does not contain any personal details and cannot be tracked back to the user please let me know, so I can be reassured that my current set up is fine and I am not causing any privacy issues! This post did seem to indicate you may possibly be able to fetch personal details?? https://stackoverflow.com/questions/55782166/how-do-i-fetch-any-info-about-user-that-modified-ckrecord
3
0
290
Mar ’25
How to diagnose spurious SwiftDataMacros error
I have a Package.swift file that builds and runs from Xcode 15.2 without issue but fails to compile when built from the command line ("swift build"). The swift version is 6.0.3. I'm at wits end trying to diagnose this and would welcome any thoughts. The error in question is error: external macro implementation type 'SwiftDataMacros.PersistentModelMacro' could not be found for macro 'Model()'; plugin for module 'SwiftDataMacros' not found The code associated with the module is very vanilla. import Foundation import SwiftData @Model public final class MyObject { @Attribute(.unique) public var id:Int64 public var vertexID:Int64 public var updatedAt:Date public var codeUSRA:Int32 init(id:Int64, vertexID:Int64, updatedAt:Date, codeUSRA:Int32) { self.id = id self.vertexID = vertexID self.updatedAt = updatedAt self.codeUSRA = codeUSRA } public static func create(id:Int64, vertexID:Int64, updatedAt:Date, codeUSRA:Int32) -> MyObject { MyObject(id: id, vertexID: vertexID, updatedAt: updatedAt, codeUSRA: codeUSRA) } } Thank you.
1
1
281
Mar ’25
SwiftData duplicates values inside array on insert()
After copying and inserting instances I am getting strange duplicate values in arrays before saving. My models: @Model class Car: Identifiable { @Attribute(.unique) var name: String var carData: CarData func copy() -> Car { Car( name: "temporaryNewName", carData: carData ) } } @Model class CarData: Identifiable { var id: UUID = UUID() var featuresA: [Feature] var featuresB: [Feature] func copy() -> CarData { CarData( id: UUID(), featuresA: featuresA, featuresB: featuresB ) } } @Model class Feature: Identifiable { @Attribute(.unique) var id: Int @Attribute(.unique) var name: String @Relationship( deleteRule:.cascade, inverse: \CarData.featuresA ) private(set) var carDatasA: [CarData]? @Relationship( deleteRule:.cascade, inverse: \CarData.featuresB ) private(set) var carDatasB: [CarData]? } The Car instances are created and saved to SwiftData, after that in code: var fetchDescriptor = FetchDescriptor<Car>( predicate: #Predicate<Car> { car in car.name == name } ) let cars = try! modelContext.fetch( fetchDescriptor ) let car = cars.first! print("car featuresA:", car.featuresA.map{$0.name}) //prints ["green"] - expected let newCar = car.copy() newCar.name = "Another car" newcar.carData = car.carData.copy() print("newCar featuresA:", newCar.featuresA.map{$0.name}) //prints ["green"] - expected modelContext.insert(newCar) print("newCar featuresA:", newCar.featuresA.map{$0.name}) //prints ["green", "green"] - UNEXPECTED! /*some code planned here modifying newCar.featuresA, but they are wrong here causing issues, for example finding first expected green value and removing it will still keep the unexpected duplicate (unless iterating over all arrays to delete all unexpected duplicates - not optimal and sloooooow).*/ try! modelContext.save() print("newCar featuresA:", newCar.featuresA.map{$0.name}) //prints ["green"] - self-auto-healed??? Tested on iOS 18.2 simulator and iOS 18.3.1 device. Minimum deployment target: iOS 17.4 The business logic is that new instances need to be created by copying and modifying previously created ones, but I would like to avoid saving before all instances are created, because saving after creating each instance separately takes too much time overall. (In real life scenario there are more than 10K objects with much more properties, updating just ~10 instances with saving takes around 1 minute on iPhone 16 Pro.) Is this a bug, or how can I modify the code (without workarounds like deleting duplicate values) to not get duplicate values between insert() and save()?
8
0
324
Mar ’25
Friend Connection ( User A / User B) Problem
I implemented the cloudkit function, where users can connect with each other. The problem is, that if User A is doing a friend request and User B is accepting the request. The friend entry is correct visible for User B but not for User A. I can see in cloud kit that after the accepted request, the friend connection is set up correctly, also with the correct userID, but it not showing up for User A (the one that send the request)
3
0
360
Mar ’25
How to force / wait for SwiftData sync on first app launch?
I have a SwiftData application that is using CloudKit. If user is on new device. How can I check and fetch data, instead of just waiting for it happen on its own randomly? For example, I have onboarding which I do not want user to go through again if they already have an active installation. Seems like SwiftData is severely limited in pretty much every way, specially any useful CloudKit debugging or control functionality.
2
0
293
Mar ’25
Is iCloud sync working?
Hello, I tried to validate if my app was properly syncing to the cloud. To test this, I created some data in the app, and then deleted the app, and reinstalled. I was expecting the data to still exist but it isn't. Is this a valid test or is the data expected to be deleted when app is deleted?
1
0
157
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
351
Mar ’25
Schema Migrations with CloudKit Not Working
I have not had any successful Schema Migration with CloudKit so far so I'm trying to do with with just very basic attributes, with multiple Versioned Schemas This is the code in my App Main var sharedModelContainer: ModelContainer = { let schema = Schema(versionedSchema: AppSchemaV4.self) do { return try ModelContainer( for: schema, migrationPlan: AppMigrationPlan.self, configurations: ModelConfiguration(cloudKitDatabase: .automatic)) } catch { fatalError("Could not create ModelContainer: \(error)") } }() var body: some Scene { WindowGroup { ItemListView() } .modelContainer(sharedModelContainer) } And this is the code for my MigrationPlan and VersionedSchemas. typealias Item = AppSchemaV4.Item3 enum AppMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] { [AppSchemaV1.self, AppSchemaV2.self, AppSchemaV3.self, AppSchemaV4.self] } static var stages: [MigrationStage] { [migrateV1toV2, migrateV2toV3, migrateV3toV4] } static let migrateV1toV2 = MigrationStage.lightweight( fromVersion: AppSchemaV1.self, toVersion: AppSchemaV2.self ) static let migrateV2toV3 = MigrationStage.lightweight( fromVersion: AppSchemaV2.self, toVersion: AppSchemaV3.self ) static let migrateV3toV4 = MigrationStage.custom( fromVersion: AppSchemaV3.self, toVersion: AppSchemaV4.self, willMigrate: nil, didMigrate: { context in // Fetch all Item1 instances let item1Descriptor = FetchDescriptor<AppSchemaV3.Item1>() let items1 = try context.fetch(item1Descriptor) // Fetch all Item2 instances let item2Descriptor = FetchDescriptor<AppSchemaV3.Item2>() let items2 = try context.fetch(item2Descriptor) // Convert Item1 to Item3 for item in items1 { let newItem = AppSchemaV4.Item3(name: item.name, text: "Migrated from Item1 on \(item.date)") context.insert(newItem) } // Convert Item2 to Item3 for item in items2 { let newItem = AppSchemaV4.Item3(name: item.name, text: "Migrated from Item2 with value \(item.value)") context.insert(newItem) } try? context.save() } ) } enum AppSchemaV1: VersionedSchema { static var versionIdentifier: Schema.Version = Schema.Version(1, 0, 0) static var models: [any PersistentModel.Type] { [Item1.self] } @Model class Item1 { var name: String = "" init(name: String) { self.name = name } } } enum AppSchemaV2: VersionedSchema { static var versionIdentifier: Schema.Version = Schema.Version(2, 0, 0) static var models: [any PersistentModel.Type] { [Item1.self] } @Model class Item1 { var name: String = "" var date: Date = Date() init(name: String) { self.name = name self.date = Date() } } } enum AppSchemaV3: VersionedSchema { static var versionIdentifier: Schema.Version = Schema.Version(3, 0, 0) static var models: [any PersistentModel.Type] { [Item1.self, Item2.self] } @Model class Item1 { var name: String = "" var date: Date = Date() init(name: String) { self.name = name self.date = Date() } } @Model class Item2 { var name: String = "" var value: Int = 0 init(name: String, value: Int) { self.name = name self.value = value } } } enum AppSchemaV4: VersionedSchema { static var versionIdentifier: Schema.Version = Schema.Version(4, 0, 0) static var models: [any PersistentModel.Type] { [Item1.self, Item2.self, Item3.self] } @Model class Item1 { var name: String = "" var date: Date = Date() init(name: String) { self.name = name self.date = Date() } } @Model class Item2 { var name: String = "" var value: Int = 0 init(name: String, value: Int) { self.name = name self.value = value } } @Model class Item3 { var name: String = "" var text: String = "" init(name: String, text: String) { self.name = name self.text = text } } } My experiment was: To create Items for every version of the schema Updating the typealias along the way to reflect the latest Item version. Updating the Schema in my ModelContainer to reflect the latest Schema Version. By AppSchemaV4, I have expected all my Items to be displayed/migrated to Item3, but it does not seem to be the case. I can only see newly created Item3 records. My question is, is there something wrong with how I'm doing the migrations? or are migrations not really working with CloudKit right now?
1
0
355
Mar ’25
iOS 17.2 Update, Confusing SwiftData Update !
Hi, Before the iOS 17.2 update the saving behavior of SwiftData was very straightforward, by default it saves to persistence storage and can be configured to save in memory only. Now it saves to memory by default and to make it save to persistence storage we need to use modelContext.Save(). But if we don't quit the App the changes will be saved after a while to persistence storage even without running modelContext.Save() ! How confusing can that be for both developer and the user ! Am I missing something here ? -- Kind Regards
3
0
391
Mar ’25
dual predicate search using CoreData
I have a very simple CoreData model that has 1 entity and 2 attributes. This code works fine: .onChange(of: searchText) { _, text in evnts.nsPredicate = text.isEmpty ? nil :NSPredicate(format: "eventName CONTAINS %@ " , text ) but I'd like to also search with the same text string for my second attribute (which is a Date). I believe an OR is appropriate for two conditions (find either one). See attempted code below: evnts.nsPredicate = text.isEmpty ? nil : NSPredicate(format: "(eventName CONTAINS %@) OR (dueDate CONTAINS %i) " , text ) This crashes immediately %@ does the same. Is there a way to accomplish this? How is SwiftUI not an option below?
6
0
310
Mar ’25
Request to manually associate my CloudKit container with my app ID
Hello, My app has had CloudKit enabled for a while, but it's not working. I get the error "Invalid bundle ID for container". Configure CloudKit in your project from TN3164 suggests changing to a new container. I tried changing to a new container, but this leads to data loss. The article recommends: "If your CloudKit container is already used in the production environment and switching to a new container leads to data loss, consider filing a feedback report with the following information to request manually associating your CloudKit container with your app ID." Where can I request this manual association? Is there anything else I can do? Thank you for your time and assistance. I’d appreciate a prompt resolution, as this issue is blocking our update. Looking forward to guidance.
2
0
482
Mar ’25
Swift 6 Concurrency errors with ModelActor, or Core Data actors
In my app, I've been using ModelActors in SwiftData, and using actors with a custom executor in Core Data to create concurrency safe services. I have multiple actor services that relate to different data model components or features, each that have their own internally managed state (DocumentService, ImportService, etc). The problem I've ran into, is that I need to be able to use multiple of these services within another service, and those services need to share the same context. Swift 6 doesn't allow passing contexts across actors. The specific problem I have is that I need a master service that makes multiple unrelated changes without saving them to the main context until approved by the user. I've tried to find a solution in SwiftData and Core Data, but both have the same problem which is contexts are not sendable. Read the comments in the code to see the issue: /// This actor does multiple things without saving, until committed in SwiftData. @ModelActor actor DatabaseHelper { func commitChange() throws { try modelContext.save() } func makeChanges() async throws { // Do unrelated expensive tasks on the child context... // Next, use our item service let service = ItemService(modelContainer: SwiftDataStack.shared.container) let id = try await service.expensiveBackgroundTask(saveChanges: false) // Now that we've used the service, we need to access something the service created. // However, because the service created its own context and it was never saved, we can't access it. let itemFromService = context.fetch(id) // fails // We need to be able to access changes made from the service within this service, /// so instead I tried to create the service by passing the current service context, however that results in: // ERROR: Sending 'self.modelContext' risks causing data races let serviceFromContext = ItemService(context: modelContext) // Swift Data doesn't let you create child contexts, so the same context must be used in order to change data without saving. } } @ModelActor actor ItemService { init(context: ModelContext) { modelContainer = SwiftDataStack.shared.container modelExecutor = DefaultSerialModelExecutor(modelContext: context) } func expensiveBackgroundTask(saveChanges: Bool = true) async throws -> PersistentIdentifier? { // Do something expensive... return nil } } Core Data has the same problem: /// This actor does multiple things without saving, until committed in Core Data. actor CoreDataHelper { let parentContext: NSManagedObjectContext let context: NSManagedObjectContext /// In Core Data, I can create a child context from a background context. /// This lets you modify the context and save it without updating the main context. init(progress: Progress = Progress()) { parentContext = CoreDataStack.shared.newBackgroundContext() let childContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) childContext.parent = parentContext self.context = childContext } /// To commit changes, save the parent context pushing them to the main context. func commitChange() async throws { // ERROR: Sending 'self.parentContext' risks causing data races try await parentContext.perform { try self.parentContext.save() } } func makeChanges() async throws { // Do unrelated expensive tasks on the child context... // As with the Swift Data example, I am unable to create a service that uses the current actors context from here. // ERROR: Sending 'self.context' risks causing data races let service = ItemService(context: self.context) } } Am I going about this wrong, or is there a solution to fix these errors? Some services are very large and have their own internal state. So it would be very difficult to merge all of them into a single service. I also am using Core Data, and SwiftData extensively so I need a solution for both. I seem to have trapped myself into a corner trying to make everything concurrency save, so any help would be appreciated!
6
0
719
Mar ’25