Is it possible to use CloudKit and add integrations, Google Drive for example. If possible, how?
CloudKit
RSS for tagStore 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
Sort by:
Post
Replies
Boosts
Views
Activity
I'm continually getting an error with a new CloudKit container when I try to save data.
error: Couldn't get container configuration from the server for container "iCloud.com.***.***"
here's the class:
private var db = CKContainer(identifier: "iCloud.com.***.***").privateCloudDatabase
func addTask(taskItem: TaskItem) async throws {
checkStatus()
do {
try await db.save(taskItem.record)
} catch {
print("error: \(error.localizedDescription)")
}
}
func checkStatus() {
let id = CKContainer(identifier: "iCloud.com.***.***").containerIdentifier
print(id ?? "unknown")
Task {
let status = try await CKContainer(identifier: "iCloud.com.***.***").accountStatus()
switch status {
case .available:
print("available")
case .noAccount:
print("no account")
case .restricted:
print("restricted")
case .couldNotDetermine:
print("could not determine")
case .temporarilyUnavailable:
print("temporarily unavailable")
@unknown default: break
}
}
}
The account status reports as available but gives the error on an attempt to save.. I'm trying to work out what I might be doing wrong..
Hello, I`m working on an app that uses CloudKit and CKShare, but the app has 2 different targets, one for professional and one for patients, and theoretically the target of the professional sends the CKShare and the target of the patient should accept, but the ckshare tries to always open the target of the profissional, I would like to know if the are any way to configure the CKShare to oppen the target od the patients
While reading CkSyncEngine demo project code, I don't find the code to remove items in syncEngine.state.pendingRecordZoneChanges explicitly. I suspect it might occur in two possible places: nextRecordZoneChangeBatch() or ``nextRecordZoneChangeBatch()`, but I can't figure out how it occurs.
nextRecordZoneChangeBatch() has the following code:
let batch = await CKSyncEngine.RecordZoneChangeBatch(pendingChanges: changes) { recordID in
if let contact = contacts[recordID.recordName] {
let record = contact.lastKnownRecord ?? CKRecord(recordType: Contact.recordType, recordID: recordID)
contact.populateRecord(record)
return record
} else {
// We might have pending changes that no longer exist in our database. We can remove those from the state.
syncEngine.state.remove(pendingRecordZoneChanges: [ .saveRecord(recordID) ])
return nil
}
}
(I'll ignore the syncEngine.state.remove(pendingRecordZoneChanges:) in the else clause, because it's unrelated)
Could it be that CKSyncEngine.RecordZoneChangeBatch.init(pendingChanges:,recordProvider:) automatically remove a CKRecord when the recordProvider: closure returns a non-nil value? I checked its document, but it doesn't say anything about this.
Thanks for any help.
I am getting the following error while trying to delete a Record Type in Dev container. How do I solve it?
invalid attempt to delete user record type
I have a quesiton on .accountChange handler code in CKSyncEngine demo project. Below is the code in handleAccountChange():
if shouldDeleteLocalData {
try? self.deleteLocalData() // This error should be handled, but we'll skip that for brevity in this sample app.
}
if shouldReUploadLocalData {
let recordZoneChanges: [CKSyncEngine.PendingRecordZoneChange] = self.appData.contacts.values.map { .saveRecord($0.recordID) }
self.syncEngine.state.add(pendingDatabaseChanges: [ .saveZone(CKRecordZone(zoneName: Contact.zoneName)) ])
self.syncEngine.state.add(pendingRecordZoneChanges: recordZoneChanges)
}
IMHO, when user switches account, the most important thing is to reload data from the new account's document folder. However, I can't see this is done anywhere. In above code, if shouldDeleteLocalData is false, self.appData would still hold the previous account's local data. That seems very wrong. Am I missing something?
It would be best if iOS restarts all applications when user switches account. If that's not the case (I guess so, otherwise there is no point to handle .accountChange in the app), I think application should implement an API to re-initialize itself.
EDIT: after looking at the code again, I realize that the following code makes sure shouldDeleteLocalData is always true when user switching accounts. So the code doesn't leak the previous account's data, though I still think it has an issue - it doesn't load the new account's data.
case .switchAccounts:
shouldDeleteLocalData = true
shouldReUploadLocalData = false
When using iCloud account with push in Apple mail app.
The badge number of unread email is not syncing across devices.
If I read an email on my iPhone my iPad mail app badge won’t update until I click into the app and wait for the update.
Is there any fix of this?
After upgrading to iOS 18, my Core Data stack using NSPersistentCloudKitContainer in a shared App Group container stopped syncing correctly. The persistent store configuration, which previously worked in iOS 17, now experiences delayed or missing sync updates between devices. Then the app freezes and writes terminal the same error detail (which I provided) too many times.
The debug logs from the CloudKit mirroring delegate (NSCloudKitMirroringDelegate) show repetitive notifications but no updates in persistent history. Additionally, the persistent history tracking key appears unresponsive to local changes, causing transactions to fail in updating or syncing as expected.
Key setup details:
Core Data is set up within an App Group container using NSPersistentCloudKitContainer.
NSPersistentHistoryTrackingKey and NSPersistentStoreRemoteChangeNotificationPostOptionKey options are set to true.
Any insights into changes in iOS 18 Core Data or CloudKit handling with NSPersistentCloudKitContainer, especially around history tracking and sync delays, would be greatly appreciated. Thank you.
Error Detail
file:///private/var/mobile/Containers/Shared/AppGroup/BF95D309-EBE9-485E-B5CE-AA17097F7B60/[AppName]Database.sqlite
CoreData: debug: CoreData+CloudKit: -[NSCloudKitMirroringDelegate managedObjectContextSaved:](3123): <NSCloudKitMirroringDelegate: 0x3032b4870>: Observed context save: <NSPersistentStoreCoordinator: 0x302694bd0> - <NSManagedObjectContext: 0x3036b1a00>
CoreData: debug: CoreData+CloudKit: -[NSCloudKitMirroringDelegate remoteStoreDidChange:](3166): <NSCloudKitMirroringDelegate: 0x3032b4870>: Observed remote store notification: <NSPersistentStoreCoordinator: 0x302694bd0> - 090C4244-0101-4DEF-90D6-1260570F47A5 - <NSPersistentHistoryToken - {
"090C4244-0101-4DEF-90D6-1260570F47A5" = 9;
}> -
Persistence.swift
struct PersistenceController {
let container: NSPersistentCloudKitContainer
static let shared = PersistenceController()
static var preview: PersistenceController = {PersistenceController()}()
init() {
container = NSPersistentCloudKitContainer(name: "[AppName]")
// Configure CloudKit for the default container
if let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.[CompanyName].[AppName]") {
let storeURL = url.appendingPathComponent("[AppName]Database.sqlite")
let description = container.persistentStoreDescriptions.first
description?.url = storeURL
description?.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description?.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
container.persistentStoreDescriptions = [description].compactMap { $0 }
}
container.loadPersistentStores { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}
}
In CloudKit console, i have a key named "Name" with String data type and i want to filter my query by that key. I can only query two record with name "Star" and "Kaizen", and i can't query the rest of the records. Can you help me with that.
WhatsApp is automatically suffixing a number to the device name in the list of Linked devices shown in WhatsApp app settings. The suffixed number has no correlation to the actual number of linked devices at that time. For example, a number “2” is suffixed to the device name in list of Linked devices shown in WhatsApp, even though that computer/ device is the only one shown as a linked device.
If we try to edit the device name to remove the suffixed digit, it does not move forward.
I think it has something to do with the restoration of chats from cloud, because the suffixing happens subsequent to the restoration of chats from cloud.
Whatsapp does not respond to emails about this issue.
Anyone else?
I'm trying to look at what the best way to do thumbnails for images that are saved in core data, which are being synced across multiple devices.
I know I can save a lower quality version into core data, but I'm wondering if there's a better way of doing it.
I've come across quick look thumbnailing which looks like what I want, but I'm not sure if it can be adapted for core data as its using file paths, whereas the images are stored in a data type property in core data.
From what I can tell, I'd have to save the image locally, produce the thumbnail, then delete the local image
My app is able to receive data updates when it is in foreground.
however, when i move it in background then sync engine stops syncing until I again move app to foreground.
My App requires access to iCloud. I used to be able to get the User's name components (family+given name) using:
let dummyZone = CKRecordZone (zoneName: UUID().uuidString)
let dummyShare = CKShare (recordZoneID: dummyZone.zoneID)
Persistence.logger.notice ("\(#function): Dummy Zone: \(dummyZone.zoneID.zoneName)")
// Save the dummyZone and then the dummyShare (for/in the dummyZone)
let _ = try await container.privateCloudDatabase.save (dummyZone)
let _ = try await container.privateCloudDatabase.save (dummyShare)
// Extract the dummyShare's owner's identity - which is 'us/me'
let userIdentity = dummyShare.owner.userIdentity
where the resulting userIdentity had a filled out nameComponents. Now, recently, it seems to be empty.
Did something change in the interfaces?
I've also tried, more directly:
let userRecordID = try await container.userRecordID()
let userParticipant = try await container.shareParticipant(forUserRecordID: userRecordID)
let userIdentity = userParticipant.userIdentity
and still nameComponents is empty.
Given that my App requires iCloud, is there a way to get (familyName,givenName)?
Use CloudKit's ckqueryoperation's recordmatchedblock in Swift 6.0, which always crashes, but works fine in Swift 5:
func fetchAllRecords() async throws {
let predicate = NSPredicate(format: "Topics = %@", "Integrations")
let query = CKQuery(recordType: "PureMList", predicate: predicate)
let operation = CKQueryOperation(query: query)
operation.recordMatchedBlock = { recordID, result in
switch result {
case .success(let record):
DispatchQueue.main.async {
// Ensure UI updates happen here
print("Fetched record: \(record)")
// Update your UI elements here
}
case .failure(let error):
// Handle the error
print("Error fetching record with ID \(recordID): \(error)")
}
}
// Ensure you're using the correct database
publicDatabase.add(operation)
}
Hi,
I did cloudkit synchronization using swiftdata.
However, synchronization does not occur automatically, and synchronization occurs intermittently only when the device is closed and opened.
For confirmation, after changing the data in Device 1 (saving), when the data is fetched from Device 2, there is no change.
I've heard that there's still an issue with swiftdata sync and Apple is currently troubleshooting it, is the phenomenon I'm experiencing in the current version normal?
I created a new index on two record types on Oct 12th. I still cannot query the records using the new queryable index on records that were created before that date. There is no indication in the schema history that the reindexing has started, completed, failed, or still in progress.
What is the expectation for new indices being applied to existing records? Well over a week seems unacceptable for a database that has maybe 5000 records across a few record types.
When I query my data using an old index and an old record field, I get hundreds of matching results so I know the data is there.
FB15554144 - CloudKit / CloudKit Console: PRODUCTION ISSUE - Query against index created two weeks ago not returning all data as expected
I'm considering using CloudKit in my app (it doesn't use Core Data) and have read as many materials as I can find. I haven't fully grasped it yet and have a basic question on CKRecord.Reference. Does CloudKit guarantee CKRecord.Reference value is always valid? By valid I mean the target CkRecord pointed by the CKRecord.Reference exists in the database.
Let's consider an example. Suppose there are two tables: Account and Transaction:
Account Table:
AccountNumber Currency Rate
------------- -------- ----
a1 USD 0.03
Transaction Table:
TransactionNumber AccountNumber Amount
----------------- ------------- ------
t1 a1 20
Now suppose user does the following:
User first deletes account a1 and its associated transactions t1 on device A. The device saves the change to cloud.
Then user adds a new transaction t2 to account a1 on device B, before the device receives the change made in step 1 from cloud. Since a1 hasn't been deleted on device B, the operation should succeed locally. The device tries to save the change to cloud too.
My questions:
Q1) Will device B be able to save the change in step 2 to cloud?
I hope it would fail, because otherwise it would lead to inconsistent data. But I find the following in CKModifyRecordsOperation doc (emphasis mine), which implies CloudKit allows invalid reference:
During a save operation, CloudKit requires that the target record of the parent reference, if set, exists in the database or is part of the same operation; all other reference fields are exempt from this requirement.
(BTW, I think the fact that, when using CloudKit, Core Data requires all relations must be optional also indicates that CloudKit can't guarantee relation is always valid, though I think that is mainly an issue on client side caused by data transfer size. The above example, however, is different in that it's an issue on cloud side - the data on cloud is inconsistent).
I also find the following in the document. However, I don't think it helps in the above example, because IIUC CloudKit can only detect conflict when the changes on the same record but the changes in step 1 and step 2 are on different records.
Because records can change between the time you fetch them and the time you save them, the save policy determines whether new changes overwrite existing changes. By default, the operation reports an error when there’s a newer version on the server.
If the above understanding is correct, however, I don't understand why the same document has the following requirement, which implies CloudKit doesn't allow invalid reference:
When creating two new records that have a reference between them, use the same operation to save both records at the same time.
Q2) Suppose CloudKit allows invalid reference on cloud side (that is, device B successfully saves the change in step 2 to cloud) , I wonder what's the best practice to deal with it?
I think the issue is different from the optional relation requirement in Core Data when using CloudKit, because in that case the data is consistent on cloud side and eventually the client will receive complete data. In the above example, however, the data on cloud is inconsistent so the client has to remedy it somehow (although client has little information helping it).
One approach I think of is to avoid the issue in the first place. My idea is to maintain a counter in the database and requires client to increase the counter (it's not Lamport clock. BTW, is it possible to use Lamport clock in this case?) when making any change. This should help CloudKit to detect conflict (though I can't think out a good strategy on how client should deal with it. A simple one is perhaps to prompt user to select one copy). However, this approach effectively uses cloud as a centralized server, which I suspect isn't the typical way how people use CloudKit, and it requires clients to maintain local counter value in various situations. I wonder what's the typical approach? Am I missing something?
Thanks for any help.
I have Core Data setup with a NSPersistentCloudKitContainer as my container, I've added a container identifier and I see my data on CloudKit's database here when I use "Act As iCloud Account". Here's what I have under capabilities in Xcode
However, on my device when I go to Settings > Apple Account > iCloud > Saved to iCloud and switch off my app, all the data saved to Core Data is removed. I suspected this working as intended. When I switch it back on, all the data comes back. However (x2), the support page here says it should remain on the device:
When you turn it off, the app no longer connects with iCloud, so your data exists only on your device
Am I missing something in how I integrated Core Data in Xcode? Do I need to explicitly configure something with Apple's SDK to get the behavior described in the support page?
I've noticed for some of Apple's apps, when you switch off iCloud there's an action sheet asking what you'd like to do with the local data. I figured this was Apple's magic without sharing especially since the buttons looked different
Stocks
Safari
Contacts
However (x3), not all apps that had this option offered "Keep on My iPhone", so perhaps the supported behavior is to remove what's on the device and these Apple apps implemented their own support to keep a copy on the device.
Reminders
I've tried testing some 3rd-party apps but couldn't convince myself they were using Core Data with iCloud enabled. Instead, it looked like they were using iCloud as a backup
I have a project that currently has data saved locally and I'm trying to get it to sync over multiple devices.
Currently basic data is syncing perfectly fine, but I'm having issues getting the images to convert to data. From what I've researched it because I'm using a UIImage to convert and this caches the image
It works fine when there's only a few images, but if there's several its a pain
The associated code
func updateLocalImages() {
autoreleasepool {
let fetchRequest: NSFetchRequest<Project> = Project.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "converted = %d", false)
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Project.statusOrder?.sortOrder, ascending: true), NSSortDescriptor(keyPath: \Project.name, ascending: true)]
do {
let projects = try viewContext.fetch(fetchRequest)
for project in projects {
currentPicNumber = 0
currentProjectName = project.name ?? "Error loading project"
if let pictures = project.pictures {
projectPicNumber = pictures.count
for pic in pictures {
currentPicNumber = currentPicNumber + 1
let picture : Picture = pic as! Picture
if let imgData = convertImage(picture: picture) {
picture.pictureData = imgData
}
}
project.converted = true
saveContext()
}
}
} catch {
print("Fetch Failed")
}
}
}
func convertImage(picture : Picture)-> Data? {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let path = paths[0]
if let picName = picture.pictureName {
let imagePath = path.appendingPathComponent(picName)
if let uiImage = UIImage(contentsOfFile: imagePath.path) {
if let imageData = uiImage.jpegData(compressionQuality: 0.5) {
return imageData
}
}
}
return nil
}```
Ive been getting this error on an app in the dev environment since iOS16. it continues to happen in the latest iOS release (iOS18).
After this error/warning, CoreData_CloudKit stops syncing and the only way to fix it is to delete the app from all devices, reset the CloudKit dev environment, reload the schema and reload all data. im afriad that if I ever go live and get this error in production there won't be a way to fix it given I cant go and reset the production CloudKit environment.
It doesn't happen straight away after launching my app in a predictable manner, it can take several weeks to happen.
Ive posted about this before here and haven't got a response. I also have a feedback assistant issue submitted in 2022 as part of ios16 beta that is still open: FB10392936 for a similar issue that caused the same error.
would like to submit a code level support query but it doest seem to have anything to do with my code - but rather the Apple core data CloudKit syncing mechanism.
anyone have any similar issues or a way forward?
> error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _requestAbortedNotInitialized:](2200): <NSCloudKitMirroringDelegate: 0x301e884b0> - Never successfully initialized and cannot execute request '<NSCloudKitMirroringImportRequest: 0x3006f5a90> D823EEE6-EFAE-4AF7-AFED-4C9BA708703B' due to error: Error Domain=NSCocoaErrorDomain Code=4864 "*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x73, 0x61, 0x6d)" UserInfo={NSDebugDescription=*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x73, 0x61, 0x6d)}