CloudKit

RSS for tag

Store structured app and user data in iCloud containers that can be shared by all users of your app using CloudKit.

Posts under CloudKit tag

200 Posts

Post

Replies

Boosts

Views

Activity

Recovering Customer's Data After iCloud Migration
I have encountered an issue with a customer’s data access after they migrated to a different iCloud account, and I’m looking for guidance. The Situation: The customer was logged into their account on my app, which was associated with a specific iCloud account (iCloud A). They had all their app data available while using iCloud A. The customer then switched to a new iCloud account (iCloud B) on the same device, while still using the same app account. After switching iCloud accounts, their data is no longer visible in the app or my CloudKit dashboard. My Investigation: I accessed the customer’s CloudKit data via the CloudKit Console, acting as their iCloud account. I couldn’t find the private database zone or any of their records when accessing iCloud A through the console. I don’t believe the data was deleted since actions performed under iCloud B shouldn’t affect data stored in iCloud A. My Hypothesis: I suspect that the customer’s old iCloud account (iCloud A) may have downgraded or stopped paying for iCloud storage. If the iCloud subscription is inactive or expired, could that prevent me from accessing their CloudKit data? Would renewing the iCloud subscription for iCloud A restore access to the missing data? Questions: Does an unpaid or expired iCloud account restrict access to CloudKit records, even if they weren’t deleted? Would paying for iCloud storage again restore the data previously stored in CloudKit? Is there any way to recover the customer’s CloudKit data if they are unable to access their old iCloud account? If anyone has a simpler approach to recovering the customer’s iCloud-stored app data or has experience dealing with iCloud migrations like this, I’d appreciate your insights. Thank you in advance for any advice!
2
0
808
Jan ’25
Unable to download file from iCloud Documents.
I am unable to download file from iCloud Documents from my swift project. I was able to successfully upload the file to iCloud Documents but now when I try to download same file at the uploaded path. It is giving me error that I don't have permission to view the file. Please find exact error below. [ERROR] couldn't fetch remote operation IDs: NSError: Cocoa 257 "The file couldn’t be opened because you don’t have permission to view it." "Error returned from daemon: Error Domain=com.apple.accounts Code=7 "(null)""
4
0
946
Jan ’25
Cannot add participants to CoreData to share between multiple users
I have been trying to get this to work since it was announced a few years ago but with no joy. I'm struggling to get Apple's example code to behave itself too. Seems overly complex and buggy. So I set out to create a simplified version myself. I have got the database to sync with CloudKit and I can see my records in the developer dashboard. I'm trying to use container.record(for: object.objectID) to get the CKRecord for it, but this always fails. The next step would be to add the participant. I try to add the participant based on this code: Button { let record = fetchRecord(for: items[0]) //hack just to use the first record for dev testing let share = CKShare(rootRecord: record) let persistenceController = PersistenceController.shared persistenceController.addParticipant( emailAddress: "andrew@ambrit.com", permission: .readWrite, share: share) { share, error in if let error = error { print("Error: \(error.localizedDescription)") } else if let share = share { print("Share updated successfully: \(share)") } } } label: { Label("Participants", systemImage: "person") } and extension PersistenceController { func addParticipant(emailAddress: String, permission: CKShare.ParticipantPermission = .readWrite, share: CKShare, completionHandler: ((_ share: CKShare?, _ error: Error?) -> Void)?) { let container = PersistenceController.shared.container let lookupInfo = CKUserIdentity.LookupInfo(emailAddress: emailAddress) let persistentStore = privatePersistentStore //share.persistentStore! container.fetchParticipants(matching: [lookupInfo], into: persistentStore) { (results, error) in guard let participants = results, let participant = participants.first, error == nil else { completionHandler?(share, error) return } participant.permission = permission participant.role = .privateUser share.addParticipant(participant) container.persistUpdatedShare(share, in: persistentStore) { (share, error) in if let error = error { print("\(#function): Failed to persist updated share: \(error)") } completionHandler?(share, error) } } } } My immediate problem is that when I call fetchRecord it doesn't find anything despite the record being available in the CloudKit dashboard. func fetchRecord(for object: NSManagedObject) -> CKRecord { let container = PersistenceController.shared.container print ("Fetching record \(object.objectID)") if let record = container.record(for: object.objectID) { print("CKRecord ID: \(record.recordID)") print("Record Name: \(record.recordID.recordName)") return record } else { fatalError("Record not found") } }
1
0
796
Jan ’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
735
Jan ’25
CoreData + CloudKit
I am having problems when I first loads the app. The time it takes for the Items to be sync from my CloudKit to my local CoreData is too long. Code I have the model below defined by my CoreData. public extension Item { @nonobjc class func fetchRequest() -> NSFetchRequest<Item> { NSFetchRequest<Item>(entityName: "Item") } @NSManaged var createdAt: Date? @NSManaged var id: UUID? @NSManaged var image: Data? @NSManaged var usdz: Data? @NSManaged var characteristics: NSSet? @NSManaged var parent: SomeParent? } image and usdz columns are both marked as BinaryData and Attribute Allows External Storage is also selected. I made a Few tests loading the data when the app is downloaded for the first time. I am loading on my view using the below code: @FetchRequest( sortDescriptors: [NSSortDescriptor(keyPath: \Item.createdAt, ascending: true)] ) private var items: FetchedResults<Item> var body: some View { VStack { ScrollView(.vertical, showsIndicators: false) { LazyVGrid(columns: columns, spacing: 40) { ForEach(items, id: \.self) { item in Text(item.id) } } } } } Test 1 - Just loads everything When I have on my cloudKit images and usdz a total of 100mb data, it takes around 140 seconds to show some data on my view (Not all items were sync, that takes much longer time) Test 2 - Trying getting only 10 items at the time () This takes the same amount of times the long one . I have added the following in my class, and removed the @FetchRequest: @State private var items: [Item] = [] // CK @State private var isLoading = false @MainActor func loadMoreData() { guard !isLoading else { return } isLoading = true let fetchRequest = NSFetchRequest<Item>(entityName: "Item") fetchRequest.predicate = NSPredicate(format: "title != nil AND title != ''") fetchRequest.fetchLimit = 10 fetchRequest.fetchOffset = items.count fetchRequest.predicate = getPredicate() fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Item.createdAt, ascending: true)] do { let newItems = try viewContext.fetch(fetchRequest) DispatchQueue.main.async { items.append(contentsOf: newItems) isLoading = false } } catch {} } Test 2 - Remove all images and usdz from CloudKit set all as Null Setting all items BinaryData to null, it takes around 8 seconds to Show the list. So as we can see here, all the solutions that I found are bad. I just wanna go to my CloudKit and fetch the data with my CoreData. And if possible to NOT fetch all the data because that would be not possible (imagine the future with 10 or 20GB or data) What is the solution for this loading problem? What do I need to do/fix in order to load lets say 10 items first, then later on the other items and let the user have a seamlessly experience? Questions What are the solutions I have when the user first loads the app? How to force CoreData to query directly cloudKit? Does CoreData + CloudKit + NSPersistentCloudKitContainer will download the whole CloudKit database in my local, is that good???? Storing images as BinaryData with Allow external Storage does not seems to be working well, because it is downloading the image even without the need for the image right now, how should I store the Binary data or Images in this case?
1
0
874
Jan ’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
568
Jan ’25
Database not deploying to CloudKit
I am trying to port my application over to CloudKit. My app worked fine before, but then I made scheme of changes and am trying to deploy to a new container. For some reason, the database is not being created after I create the container through Xcode. I think I have configured the app correctly and a container was created, but no records were deployed. My app current stores data locally on individual devices just fine but they don't sync with each other. That's why I would like to use CloudKit. See screenshot from Xcode of where I have configured the container. I also have background notifications enabled. Also see screenshot from console where the container has been created, but no records have been. Any suggestions would be greatly appreciated. Thank you
7
0
954
Jan ’25
SwiftData data duplication
I've got an application built on top of SwiftData (+ CloudKit) which is published to App Store. I've got a problem where on each app update, the data saved in the database is duplicated to the end user. Obviously this isn't wanted behaviour, and I'm really looking forward to fixing it. However, given the restrictions of SwiftData, I haven't found a single fix for this. The data duplication happens automatically on the first initial sync after the update. My guess is that it's because it doesn't detect the data already in the device, so it pulls all data from iCloud and appends it to the database where data in reality exists.
1
0
871
Jan ’25
SwiftData and CloudKit Development vs. Production Database
Hi, I'm working on a macOS app that utilizes SwiftData to save some user generated content to their private databases. It is not clear to me at which point the app I made starts using the production database. I assumed that if I produce a Release build that it will be using the prod db, but that doesn't seem to be the case. I made the mistake of distributing my app to users before "going to prod" with CloudKit. So after I realized what I had done, I inspected my CloudKit dashboard and records and I found the following: For my personal developer account the data is saved in the Developer database correctly and I can inspect it. When I use the "Act as iCloud account" feature and use one of my other accounts to inspect the data, I notice that for the other user, the data is neither in the Development environment nor the Production environment. Which leads me to believe it is only stored locally on that user's machine, since the app does in fact work, it's just not syncing with other devices of the same user. So, my question is: how do I "deploy to production"? I know that there is a Deploy Schema Changes button in the CloudKit dashboard. At which point should I press that? If I press it now, before distributing a new version of my app, will that somehow "signal" the already running apps on user's machines to start using the Production database? Is there a setting in Xcode that I need to check for my Release build, so that the app does in fact start using the production db? Is there a way to detect in the code whether the app is using the Production database or not? It would be useful so I can write appropriate migration logic, since I don't want to loose existing data users already have saved locally.
3
0
1.2k
Jan ’25
Persistent CloudKit Internal Error
I have integrated CloudKit into a CoreData application and am ready to deploy the schema to production but keep getting an "internal error" when trying to deploy to production or reset my CloudKit environment. I have attached images of what I am seeing including one of the console error. Is there any way to resolve this?
5
1
646
Jan ’25
SwiftData and 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
I get this red warning in Xcode every time my app is syncing to the iCloud. My model has only basic types and enum that conform to Codable so i'm not sure what is the problem. App is working well, synchronization works. But the warning doesn't look good. Maybe someone has idea how to debug it.
2
0
894
Dec ’24
Why is data not encrypted on icloud.developer.apple.com when i am using encrypted field
Here is my sample code of integration with iCloud let dbName = "GroceryItem1" let fieldName = "todoTitle1" @objc func saveItem(name: String) { let record = CKRecord(recordType: dbName) record.encryptedValues[fieldName] = name database.save(record) { record, error in if error == nil { DispatchQueue.main.asyncAfter(deadline: .now() + 2) { self.fetchItems() } } else { print("Error saving item: \(error?.localizedDescription ?? "Unknown error")") } } } Now my code works fine but what i don't understand is when i login to icloud.developer.apple.com why am i able to see the data, why is it not encrypted? My database is private as well If i go to record types i can see the recordfield is encrypted as shown in below screenshot
2
0
312
Dec ’24
App Automatically Logging Out for Some Users
Hello, We’re experiencing an issue in our app where a subset of users are being logged out automatically without any apparent reason. This is impacting both iOS 16 and iOS 17 users (though it’s hard to confirm if it’s platform-specific). Here’s a breakdown of the situation: Symptoms Some users report being logged out of the app randomly, even after remaining active. The issue doesn’t seem to affect all users—just a specific subset. Users are prompted to log in again, and once they do, the app behaves as expected until the issue recurs.
1
0
489
Dec ’24
Field recordName is not marked queryable
I'm using NSPersistentCloudKitContainer and in the CloudKit dashboards I have added indexes for all my records modifiedTimestamp queryable, modifiedTimestamp sortable and recordName queryable. But I'm still getting this warning message in the console. <CKError 0x302acf0c0: "Invalid Arguments" (12/2015); server message = "Field 'recordName' is not marked queryable"; op = FF68EFF8D501AED8; uuid = 12C5C84B-EA9B-41A6-AD85-34023827E6FA; container ID = "z.y.x"> error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _importFinishedWithResult:importer:](1400): <PFCloudKitImporter: 0x30316c1c0>: Import failed with error: <CKError 0x302acf0c0: "Invalid Arguments" (12/2015); server message = "Field 'recordName' is not marked queryable"; op = FF68EFF8D501AED8; uuid = 12C5C84B-EA9B-41A6-AD85-34023827E6FA; container ID = "z.y.x"> error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate recoverFromError:](2312): <NSCloudKitMirroringDelegate: 0x301b1cd20> - Attempting recovery from error: <CKError 0x302acf0c0: "Invalid Arguments" (12/2015); server message = "Field 'recordName' is not marked queryable"; op = FF68EFF8D501AED8; uuid = 12C5C84B-EA9B-41A6-AD85-34023827E6FA; container ID = "z.y.x"> error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _recoverFromError:withZoneIDs:forStore:inMonitor:](2622): <NSCloudKitMirroringDelegate: 0x301b1cd20> - Failed to recover from error: CKErrorDomain:12 Recovery encountered the following error: (null):0 error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate resetAfterError:andKeepContainer:](612): <NSCloudKitMirroringDelegate: 0x301b1cd20> - resetting internal state after error: <CKError 0x302acf0c0: "Invalid Arguments" (12/2015); server message = "Field 'recordName' is not marked queryable"; op = FF68EFF8D501AED8; uuid = 12C5C84B-EA9B-41A6-AD85-34023827E6FA; container ID = "z.y.x"> error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _requestAbortedNotInitialized:](2200): <NSCloudKitMirroringDelegate: 0x301b1cd20> - Never successfully initialized and cannot execute request '<NSCloudKitMirroringImportRequest: 0x300738eb0> A3F23AAC-F820-4044-B4B9-28DFAC4DE8D7' due to error: <CKError 0x302acf0c0: "Invalid Arguments" (12/2015); server message = "Field 'recordName' is not marked queryable"; op = FF68EFF8D501AED8; uuid = 12C5C84B-EA9B-41A6-AD85-34023827E6FA; container ID = "z.y.x">
2
0
942
Dec ’24
CloudKit error - CKErrorRequestRateLimited
First query works fine. If next query comes within 30 seconds of first query it generates a CKErrorRequestRateLimited (error.code==7) error telling me to try after a time such that there would be 30 seconds between queries. <CKError 0x30299dd70: "Request Rate Limited" (7/2061); "Operation throttled by previous server http 503 reply. Retry after 20.5 seconds. (Other operations may be allowed.)"; Retry after 20.5 seconds>
2
0
913
Dec ’24
iCloudKit Unable to Deploy Container to Production Environment
When attempting to deploy schema changes in the iCloudKit Database by clicking the Deploy Schema Changes button, a Confirm Deployment dialog appears, showing an error: “Internal error”. The following error details were observed in the JavaScript console: • description: “The request has failed due to an error.” • headers: undefined • message: “Known response error: The request has failed due to an error.” • result: • code: 400 • detailedMessage: undefined • message: “bad-request” • reason: “Internal error” • redirectUrl: undefined • requestUuid: “0c5b4af2-15c9-425f-87ea-************” • retryAfterSeconds: undefined
2
0
922
Dec ’24
Issues during CloudKit record sharing
I am trying to implement record sharing in my project, but when I try to copy the link on the UICloudSharingController, the sheet closes and the link doesn't get copied. My CloudKitManager function: public func shareTeam(_ team: Team) -> AnyPublisher<CKShare, Error> { Future { [weak self] promise in guard let self = self else { promise(.failure(CloudKitError.unknown)) return } let record = team.toCKRecord() let share = CKShare(rootRecord: record) share[CKShare.SystemFieldKey.title] = "Join \(team.name)" as CKRecordValue share.publicPermission = .readWrite let operation = CKModifyRecordsOperation(recordsToSave: [record, share], recordIDsToDelete: nil) operation.savePolicy = .ifServerRecordUnchanged operation.qualityOfService = .userInitiated operation.modifyRecordsResultBlock = { result in switch result { case .success: promise(.success(share)) case .failure(let error): promise(.failure(error)) } } self.privateDatabase.add(operation) } .eraseToAnyPublisher() } ViewModel function: func shareTeam() { guard let selectedTeam = selectedTeam else { return } CloudKitManager.shared.shareTeam(selectedTeam) .receive(on: DispatchQueue.main) .sink { [weak self] completion in switch completion { case .finished: break case .failure(let error): self?.didError = true self?.error = error } } receiveValue: { share in let sharePresenter = SharePresenter( share: share, container: CloudKitManager.shared.container, teamName: selectedTeam.name, rootRecord: selectedTeam.toCKRecord() ) sharePresenter.presentShareSheet() } .store(in: &cancellables) }
1
0
730
Dec ’24
SwiftData + CKSyncEngine
Hi, I'm building a habit tracking app for iOS and macOS. I want to use up to date technologies, so I'm using SwiftUI and SwiftData. I want to store user data locally on device and also sync data between device and iCloud server so that the user could use the app conveniently on multiple devices (iPhone, iPad, Mac). I already tried SwiftData + NSPersistentCloudKitContainer, but I need to control when to sync data, which I can't control with NSPersistentCloudKitContainer. For example, I want to upload data to server right after data is saved locally and download data from server on every app open, on pull-to-refresh etc. I also need to monitor sync progress, so I can update the UI and run code based on the progress. For example, when downloading data from server to device is in progress, show "Loading..." UI, and when downloading finishes, I want to run some app business logic code and update UI. So I'm considering switching from NSPersistentCloudKitContainer to CKSyncEngine, because it seems that with CKSyncEngine I can control when to upload and download data and also monitor the progress. My database schema (image below) has relationships - "1 to many" and "many to many" - so it's convenient to use SwiftData (and underlying CoreData). Development environment: Xcode 16.1, macOS 15.1.1 Run-time configuration: iOS 18.1.1, macOS 15.1.1 My questions: 1-Is it possible to use SwiftData for local data storage and CKSyncEngine to sync this local data storage with iCloud? 2-If yes, is there any example code to implement this? I've been studying the "CloudKit Samples: CKSyncEngine" demo app (https://github.com/apple/sample-cloudkit-sync-engine), but it uses a very primitive approach to local data storage by saving data to a JSON file on disk. It would be very helpful to have the same demo app with SwiftData implementation! 3-Also, to make sure I don't run into problems later - is it okay to fire data upload (sendChanges) and download (fetchChanges) manually with CKSyncEngine and do it often? Are there any limits how often these functions can be called to not get "blocked" by the server? 4-If it's not possible to use SwiftData for local data storage and CKSyncEngine to sync this local data storage with iCloud, then what to use for local storage instead of SwiftData to sync it with iCloud using CKSyncEngine? Maybe use SwiftData with the new DataStore protocol instead of the underlying CoreData? All information highly appreciated! Thanks, Martin
3
0
1.3k
Dec ’24