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

Async Data with iCloud
DESCRIPTION I have an App use iCloud to save data. The App had a CoreData ManagedObject 'Product', 'Product' Object had an attribute name 'count' and it is a Double Type. I need to synchronises 'count' property across multiple devices. for example: I have a devices A、B. A device set 'Product.count' = 100. B device set 'Product.count' = 50. I hope the 'Product.count' == 150 that results. how to synchronises the 'Product.count' == 150 for multiple devices. If I have more devices in future, How to get the latest 'Product.count' that it is correct result.
4
0
656
Mar ’25
Disable SwiftData CloudKit sync when iCloud account is unavailable
I have a widely-used app that lets users keep track of personal data. This data is persisted with SwiftData, and synced with CloudKit. I understand that if the user's iCloud account changes on a device (for example, user logs out or toggles off an app's access to iCloud), then NSPersistentCloudKitContainer will erase the local data records on app launch. This is intentional behavior, intended as a privacy feature. However, we are receiving regular reports from users for whom the system has incorrectly indicated that the app's access to iCloud is unavailable, even when the user hasn't logged out or toggled off permission to access iCloud. This triggers the behavior to clear the local records, and even though the data is still available in iCloud, to the user, it looks like their data has disappeared for no reason. Helping the user find and troubleshoot their iCloud app data settings can be very difficult, since in many cases the user has no idea what iCloud is, and we can't link them directly to the correct settings screen. We seem to get these reports most frequently from users whose iCloud storage is full (which feels like punishment for not paying for additional storage), but we've also received reports from users who have enough storage space available (and are logged in and have the app's iCloud data permissions toggled on). It appears to happen randomly, as far as we can tell. I found a blog post from two years ago from another app developer who encountered the same issue: https://crunchybagel.com/nspersistentcloudkitcontainer/#:~:text=The%20problem%20we%20were%20experiencing To work around this and improve the user experience, we want to use CKContainer.accountStatus to check if the user has an available iCloud account, and if not, disable the CloudKit sync before it erases the local data. I've found steps to accomplish this workaround using CoreData, but I'm not sure how to best modify the ModelContainer's configuration after receiving the CKAccountStatus when using SwiftData. I've put together this approach so far; is this the right way to handle disabling/enabling sync based on account status? import SwiftUI import SwiftData import CloudKit @main struct AccountStatusTestApp: App { @State private var modelContainer: ModelContainer? var body: some Scene { WindowGroup { if let modelContainer { ContentView() .modelContainer(modelContainer) } else { ProgressView("Loading...") .task { await initializeModelContainer() } } } } func initializeModelContainer() async { let schema = Schema([ Item.self, ]) do { let accountStatus = try await CKContainer.default().accountStatus() let modelConfiguration = ModelConfiguration( schema: schema, cloudKitDatabase: accountStatus == .available ? .private("iCloud.com.AccountStatusTestApp") : .none ) do { let container = try ModelContainer(for: schema, configurations: [modelConfiguration]) modelContainer = container } catch { print("Could not create ModelContainer: \(error)") } } catch { print("Could not determine iCloud account status: \(error)") } } } I understand that bypassing the clearing of local data when the iCloud account is "unavailable" introduces possible issues with data being mingled on shared devices, but I plan to mitigate that with warning messages when users are in this state. This would be a far more preferable user experience than what's happening now.
1
0
1.1k
Jan ’25
swift
Hi, thank you for your reply. I have checked and confirmed that all AppleUser entity fields (id, name, email, password, createdAt) are optional, relationships (posts, comments) are optional, and I assign values when creating a new object, but Core Data still throws a nilError during registration; I have uploaded my project to GitHub for your reference here: https://github.com/Kawiichao/job. If reviewing it requires any payment, please let me know in advance. Thank you very much for your kind offer—I really appreciate it!
1
0
66
Sep ’25
Errors reading not-yet-sync'd iCloud files get cached
I have an app which uses ubiquitous containers and files in them to share data between devices. It's a bit unusual in that it indexes files in directories the user grants access to, which may or may not exist on a second device - those files are identified by SHA-1 hash. So a second device scanning before iCloud data has fully sync'd can create duplicate references which lead to an unpleasant user experience. To solve this, I store a small binary index in the root of the ubiquitous file container of the shared data, containing all of the known hashes, and as the user proceeds through the onboarding process, a background thread is attempting to "prime" the ubiquitous container by calling FileManager.default.startDownloadingUbiquitousItemAt() for each expected folder and file in a sane order. This likely creates a situation not anticipated by the iOS/iCloud integration's design, as it means my app has a sort of precognition of files it should not yet know about. In the common case, it works, but there is a corner case where iCloud sync has just begun, and very, very little metadata is available (the common case, however, in an emulator), in which two issues come up: I/O may hang indefinitely, trying to read a file as it is arriving. This one I can work around by running the I/O in a thread created with the POSIX pthread_create and using pthread_cancel to kill it after a timeout. Attempts to call FileManager.default.startDownloadingUbiquitousItemAt() fails with an error Error Domain=NSCocoaErrorDomain Code=257 "The file couldn’t be opened because you don’t have permission to view it.". The permissions aspect of it is nonsense, but I can believe there's no applicable "sort of exists, sort of doesn't" error code to use and someone punted. The problem is that this same error will be thrown on any attempt to access that file for the life of the application - a restart is required to make it usable. Clearly, the error or the hallucinated permission failure is cached somewhere in the bowels of iOS's FileManager. I was hoping startAccessingSecurityScopedResource() would allow me to bypass such a cache, as it does with URL.resourceValues() returning stale file sizes and last modified times. But it does not. Is there some way to clear this state without popping up a UI with an Exit button (not exactly the desired iOS user experience)?
1
0
124
Aug ’25
Cloudkit not synching across devices after latest ios update
After a recent iOS update, my app is not synching between devices. I'm not seeing or getting any errors. CLoudKit Logs show activity, but it's not happening realtime. Even if I close and reopen the app, it won't sync between devices. It almost looks like it only has local storage now and CloudKit is not working on it anymore. STEPS TO REPRODUCE Use app on two devices with the same Apple ID. Create a user and one device and it won't show up on the other device. Vice Versa.
1
0
568
Feb ’25
CloudKit - CKContainer.m:747 error
Hi everyone, Complete newbie here. Building an app and trying to use Cloudkit. I've added the CloudKit capability, triple checked the entitlements file for appropriate keys, made sure the code signing entitlements are pointing to the correct entitlements file. I've removed and cleared all of those settings and even created a new container as well as refreshed the signing. I just can't seem to figure out why I keep getting this error: Significant issue at CKContainer.m:747: In order to use CloudKit, your process must have a com.apple.developer.icloud-services entitlement. The value of this entitlement must be an array that includes the string "CloudKit" or "CloudKit-Anonymous". Any guidance is greatly appreciated.
1
0
135
Sep ’25
UIImage causes memory to run out
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 }```
3
0
1k
Jan ’25
SwiftData Lightweight Migraton failed with VersionedSchema
Setup I am running a versionedSchema for my SwiftData model and attempting a migration. The new version contains a new attribute, with a type of a new custom enum defined in the @Model class, a default value, and a private(set). Migration was completed with a migrationPlan with nil values for willMigrate and didMigrate. Example - Previous Version @Model class MyNumber { var num: Int init() { // Init Code } } Example - Newest Version @Model class MyNumber { var num: Int private(set) var rounding: RoundAmount = MyNumber.RoundAmount.thirtyMinute init() { // Init Code } enum RoundAmount { case fiveMinute, tenMinute, thirtyMinute } } Issue Running this code, I get a swiftData error for “SwiftData/ModelCoders.swift:1585: nil value passed for a non-optional keyPath, /MyNumber.rounding” I assume this means a failure of the swiftData lightweight migration? I have reverted the version, removed private(set) and re-tried the migration with no success. Using the versionedSchema with migrationPlans, are lightweight migrations possible? Could this be an issue with the use of a custom enum? Other changes in my actual project migrated successfully so I’m lost on why I’m having this issue.
1
0
96
Apr ’25
CKSyncEngine: Can Long-Offline Devices Miss CloudKit Change Notifications?
Problem Description: When a device (Device 2) stays offline for an extended period after a record is deleted from another synced device (Device 1) via CloudKit, is it possible for Device 2 to miss the deletion notification when it reconnects, even when using CKSyncEngine? This scenario raises questions about whether CKSyncEngine can reliably sync changes if CloudKit archives or purges metadata related to deletions during the offline period. Steps to Reproduce: At time t0: · Device 1 and Device 2 sync successfully via CKSyncEngine (shared record RecordA). Device 2 goes offline. On Device 1: · Delete RecordA; sync completes via CKSyncEngine. Wait for a duration potentially exceeding CloudKit’s change retention window (if such a window exists). Bring Device 2 back online. Observe synchronization: · Expected Behavior: CKSyncEngine removes RecordA from Device 2. · Observed Behavior: RecordA remains on Device 2. Key Questions: Under these conditions, can Device 2 permanently miss the deletion event due to CloudKit’s internal metadata management? Is there a documented retention policy for CloudKit’s change history, and how does CKSyncEngine handle scenarios where this history is truncated? What is the recommended pattern to ensure no events are missed, regardless of offline duration? Clarifications Needed: · If CloudKit does discard deletion metadata after a period, is this considered a framework limitation, or should developers implement additional safeguards? · Does CKSyncEngine log warnings or errors when it detects incomplete sync histories? Environment: · CKSyncEngine with SQLite · CloudKit Private Database · iOS/macOS latest versions Thank you for clarifying how CKSyncEngine is designed to handle this edge case!
1
0
276
Feb ’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
895
Jan ’25
SwiftData serious bug with relationships and CloudKit in iOS 18.0 (Xcode 16 Beta)
Hi guys. Can someone please confirm this bug so I report it? The issue is that SwiftData relationships don't update the views in some specific situations on devices running iOS 18 Beta. One clear example is with CloudKit. I created a small example for testing. The following code creates two @models, one to store bands and another to store their records. The following code works with no issues. (You need to connect to a CloudKit container and test it on two devices) import SwiftUI import SwiftData struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var records: [Record] var body: some View { NavigationStack { List(records) { record in VStack(alignment: .leading) { Text(record.title) Text(record.band?.name ?? "Undefined") } } .toolbar { ToolbarItem { Button("Add Record") { let randomNumber = Int.random(in: 1...100) let newBand = Band(name: "New Band \(randomNumber)", records: nil) modelContext.insert(newBand) let newRecord = Record(title: "New Record \(randomNumber)", band: newBand) modelContext.insert(newRecord) } } } } } } @Model final class Record { var title: String = "" var band: Band? init(title: String, band: Band?) { self.title = title self.band = band } } @Model final class Band { var name: String = "" var records: [Record]? init(name: String, records: [Record]?) { self.name = name self.records = records } } This view includes a button at the top to add a new record associated with a new band. The data appears on both devices, but if you include more views inside the List, the views on the second device are not updated to show the values of the relationships. For example, if you extract the row to a separate view, the second device shows the relationships as "Undefined". You can try the following code. struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var records: [Record] var body: some View { NavigationStack { List { ForEach(records) { record in RecordRow(record: record) } } .toolbar { ToolbarItem { Button("Add Record") { let randomNumber = Int.random(in: 1...100) let newBand = Band(name: "New Band \(randomNumber)", records: nil) modelContext.insert(newBand) let newRecord = Record(title: "New Record \(randomNumber)", band: newBand) modelContext.insert(newRecord) } } } } } } struct RecordRow: View { let record: Record var body: some View { VStack(alignment: .leading) { Text(record.title) Text(record.band?.name ?? "Undefined") } } } Here I use a ForEach loop and move the row to a separate view. Now on the second device the relationships are nil, so the row shows the text "Undefined" instead of the name of the band. I attached an image from my iPad. I inserted all the information on my iPhone. The first three rows were inserted with the first view. But the last two rows were inserted after I extracted the rows to a separate view. Here you can see that the relationships are nil and therefore shown as "Undefined". The views are not updated to show the real value of the relationship. This example shows the issue with CloudKit, but this also happens locally in some situations. The system doesn't detect updates in relationships and therefore doesn't refresh the views. Please, let me know if you can reproduce the issue. I'm using Mac Sequoia 15.1, and two devices with iOS 18.0.
3
0
829
Apr ’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
519
Mar ’25
MAJOR Core Data Issues with iOS 18 and sdk - Data Missing for many users?!
I just released an App update the didn't touch ANYTHING to do with Core Data (nothing changed in our Coredata code for at least 8 months). The update uses SDK for iOS 18 and Xcode 16.2 and the app now requires iOS 18 and was a minor bug patch and UI improvements for recent iOS changes. Since the update we are getting a steady trickle of users on iOS 18, some who allow the App to store data in iCloud (Cloudkit) and others who do not, all reporting that after the update to our recent release ALL their data is gone?! I had not seen this on ANY device until today when I asked a friend who uses the App if they had the issue and it turned out they did, so I hooked their device up to Xcode and ALL the data in the CoreData database was gone?! They are NOT using iCloud. There were no errors or exceptions on Xcode console but a below code returned NO records at all?! Chart is custom entity and is defined as: @interface Chart : NSManagedObject {} let moc = pc.viewContext let chartsFetch = NSFetchRequest<NSFetchRequestResult>(entityName:"Charts") // Fetch all Charts do { let fetchedCharts = try moc.fetch(chartsFetch) as! [Chart] for chart in fetchedCharts { .... } } A break point inside the do on fetchedCharts show there are NO objects returned. This is a serious issue and seems like an iOS 18 thing. I saw some people talking in here about NSFetchRequest issues with iOS 18. I need some guidance here from someone Apple engineer here who knows what the status of these NSFetchrequest bugs are and what possible workarounds are. Becasue this problem will grow for me as more users update to iOS 18.
13
0
2.4k
Feb ’25
How to handle required @relationship optionals in SwiftData CloudKit?
Hi all, As you know, when using SwiftData Cloudkit, all relationships are required to be optional. In my app, which is a list app, I have a model class Project that contains an array of Subproject model objects. A Subproject also contains an array of another type of model class and this chain goes on and on. In this type of pattern, it becomes really taxxing to handle the optionals the correct way, i.e. unwrap them as late as possible and display an error to the user if unable to. It seems like most developers don't even bother, they just wrap the array in a computed property that returns an empty array if nil. I'm just wondering what is the recommended way by Apple to handle these optionals. I'm not really familiar with how the CloudKit backend works, but if you have a simple list app that only saves to the users private iCloud, can I just handwave the optionals like so many do? Is it only big data apps that need to worry? Or should we always strive to handle them the correct way? If that's the case, why does it seem like most people skip over them? Be great if an Apple engineer could weigh in.
3
0
163
Oct ’25
Bundling app with our own SQLite
Hey there, Can we bundle our app with our own version of SQLite with extensions that we want. From what I've seen, we aren't allowed to add extensions to the built in IOS SQLite, so would this be the only way to use extensions. I ask this because I want to use the spell fix extension. I couldn't find a lot of people talking about adding SQLite extensions. Thank you!
5
0
168
Aug ’25
Safe way to query for the existence of a CKRecordZone?
There's some logic in my app that first checks to see if a specific CloudKit record zone exists. If it doesn't, it creates the zone, and then my application continues on with its work. The way I've implemented this right now is by catching the zoneNotFound error when I call CKDatabase#recordZone(for:) (docs) and creating the zone when that happens: do { try await db.recordZone(for: zoneID) } catch let ckError as CKError where [.zoneNotFound, .userDeletedZone].contains(ckError.code) { // createZone is a helper function try await createZone(zoneID: zoneID, context: context) } This works great, but every time I do this, an error is logged in CloudKit Console, which creates a lot of noise and makes it harder to see real errors. Is there a way to do this without explicitly triggering a CloudKit error? I just found CKDatabase#recordZones(for:) (docs), which seems like it returns an empty array instead of throwing an error if the zone doesn't exist. Will calling that and looking for a non-empty array work just as well, but without logging lots of errors in the console?
1
0
80
Apr ’25
Accessing "iCloud Drive" folder in Files on iPhone from App written in Swift
I am trying to read and write a text file from an App written in Swift in XCode directly to the "iCloud Drive" folder in Files on the iPhone. The app worked readlly reading and writing to the Documents folder in the App container, and then readily to the "On My iPhone" folder in Files after adding 2 lines to the plist that I found in a search online. But I have been unable to get to the iCloud Drive folder. I found an item called "Enabling Document Storage in iCloud Drive" in "iCloud Design Guide" with additional plist entries that states "These settings allow iCloud Drive to provide public access to the files stored in your app’s container": NSUbiquitousContainers iCloud.com.example.MyApp NSUbiquitousContainerIsDocumentScopePublic NSUbiquitousContainerSupportedFolderLevels Any NSUbiquitousContainerName MyApp I think I changed the MyApp items appropriately. I have enabled iCloud in my App and the XCode General, and Signing entries. But this does not work. There are no error messages and no "Steps" shown in the "Capabilities" entry in Xcode. A little help? :-)
3
0
1.2k
Jan ’25
SwiftData with CloudKit in Widgets
Good morning everyone! Today I have a question about using SwiftData with CloudKit and Widgets. I recently set up my project for SwiftData and CloudKit synchronization, but for some reason, I’m not able to give my Widget access to this data. CloudKit works perfectly fine for my main app, but the Widget only shows placeholder data(the placeholder data which were defined in the get functions as catch, this is sure). I have set the CloudKit capability for my Widget extension and tried fetching data with the get-functions in the code below. I also ensured that the data model files are members of the Widget extension target and that the Widget extension uses the same CloudKit container as the main app. I wondered if it is possible and reasonable to save a copy of my CloudKit data in an App Group container, but in that case, the information shown in the Widget are not always up-to-date, so a solution that fetches data directly from CloudKit would be better. Has anyone had experience with this case? I couldn’t find much information about this problem online. In the code below, many parts have been deleted or altered because they are not relevant to the problem, as they don’t fetch data. The variables, functions, and data models in the code may sometimes have German names, but I hope you can still understand it. Thanks for your help! struct Provider: AppIntentTimelineProvider { //[Placeholder and snapshot] func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<CleverEntry> { let entry = await loadAllVariables() return Timeline(entries: [entry], policy: .after(Date().addingTimeInterval(60 * 5))) } @MainActor private func getExam() -> [PruefungM] { //Old, local version /* guard let modelContainer = try? ModelContainer(for: PruefungM.self) else { return [] } let descriptor = FetchDescriptor<PruefungM>() let PRF = try? modelContainer.mainContext.fetch(descriptor) return PRF ?? [] */ do { let configuration = ModelConfiguration(cloudKitDatabase: .private("iCloud.my_bundle_id")) let container = try ModelContainer( for: PruefungM.self, configurations: configuration ) let descriptor = FetchDescriptor<PruefungM>() return try container.mainContext.fetch(descriptor) } catch { print("❌ Error(CloudKit): \(error)") return [] } } @MainActor private func getHAF() -> [HausaufgabeM] { do { let configuration = ModelConfiguration(cloudKitDatabase: .private("iCloud.my_bundle_id")) let container = try ModelContainer( for: HausaufgabeM.self, configurations: configuration ) let descriptor = FetchDescriptor<HausaufgabeM>() return try container.mainContext.fetch(descriptor) } catch { print("❌ Error (CloudKit): \(error)") return [] } } @MainActor private func loadAllVariables() -> CleverEntry { print("Function started") let HAF = getHAF() let PRF = getExam() //handling and returning the data } }
1
0
189
Sep ’25