iCloud & Data

RSS for tag

Learn how to integrate your app with iCloud and data frameworks for effective data storage

CloudKit Documentation

Post

Replies

Boosts

Views

Activity

CloudKit: Application has malformed entitlements
Hey, For some reason I see crashes for my iOS app related to CloudKit entitlements. The crash happens on start up and it says: "CKException - Application has malformed entitlements. Found value "*" for entitlement com.apple.developer.icloud-services, expected an array of strings" I have checked my entitlements of the same build on App Store Connect and it shows "com.apple.developer.icloud-services: ( "CloudKit" )" So I am not sure why users are having this issue. I haven't been able to reproduce it. Does anyone have any idea why this is happening? Thanks
5
0
328
2w
Collaboration of iCloud Drive document with CloudKit-based live sync
In Apple Numbers and similar apps, a user can save a document to iCloud Drive, and collaborate with other users. From what I can gather, it seems to use two mechanisms: the document as a whole is synced via iCloud Drive, but when a collaboration is started, it seems to use CloudKit records to do live updates. I am working on a similar app, that saves documents to iCloud Drive (on Mac, iPad, and iPhone). Currently it only syncs via iCloud Drive, re-reading the entire (often large) document when a remote change occurs. This can lead to a delay of several seconds (up to a minute) for the document to be saved, synced to the server, synced from the server, and re-read. I'm working on adding a "live sync", i.e. the ability to see changes in as near to real-time as feasible, like in Apple's apps. The document as a whole will remain syncing via iCloud Drive. My thought is to add a CloudKit CKRecord-based sync when two or more users are collaborating on a document, recording only the diffs for quick updates. The app would no longer re-read the entire document when iCloud Drive updates it while in use, and would instead read the CloudKit records and apply those changes. This should be much faster. Is my understanding of how Apple does it correct? Does my proposed approach seem sensible? Has anyone else implemented something like this, with iCloud Drive-based documents and a CloudKit live sync? In terms of technologies, I see that Apple now has a Shared with You framework, with the ability to use a NSItemProvider to start the collaboration. Which raises the question, should I use the iCloud Drive document for the collaboration (as I do now), or the CloudKit CKShare diff? I think I'd have to use the document as a whole, both so it works with the Send Copy option, and so a user that doesn't have the document gets it when using Collaborate. Once the collaboration is underway, I'd want to start the CloudKit channel. So I guess I'd save the CKShare to the server, get its URL, and save that in the document, so another user can read that URL as part of their initial load of the document from iCloud Drive? Once two (or more) users have the document via iCloud Drive, and the CKShare via the embedded URL, I should be able to do further live-sync updates via CloudKit. If a user closes the document and re-opens it, they'd get the updates via iCloud Drive, so no need to apply any updates from before the document was opened. Does all this sound reasonable, or am I overlooking some gotcha? I'd appreciate any advice from people who have experience with this kind of syncing.
1
0
205
2w
Fatal error: Duplicate keys of type 'AnyHashable' were found in a Dictionary
I get the following fatal error when the user clicks Save in AddProductionView. Fatal error: Duplicate keys of type 'AnyHashable' were found in a Dictionary. This usually means either that the type violates Hashable's requirements, or that members of such a dictionary were mutated after insertion. As far as I’m aware, SwiftData automatically makes its models conform to Hashable, so this shouldn’t be a problem. I think it has something to do with the picker, but for the life of me I can’t see what. This error occurs about 75% of the time when Save is clicked. I'm using Xcode 16.2 and iPhone SE 2nd Gen. Any help would be greatly appreciated… Here is my code: import SwiftUI import SwiftData @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() .modelContainer(for: Character.self, isAutosaveEnabled: false) } } } @Model final class Character { var name: String var production: Production var myCharacter: Bool init(name: String, production: Production, myCharacter: Bool = false) { self.name = name self.production = production self.myCharacter = myCharacter } } @Model final class Production { var name: String init(name: String) { self.name = name } } struct ContentView: View { @State private var showingSheet = false var body: some View { Button("Add", systemImage: "plus") { showingSheet.toggle() } .sheet(isPresented: $showingSheet) { AddProductionView() } } } struct AddProductionView: View { @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) var modelContext @State var production = Production(name: "") @Query var characters: [Character] @State private var characterName: String = "" @State private var selectedCharacter: Character? var filteredCharacters: [Character] { characters.filter { $0.production == production } } var body: some View { NavigationStack { Form { Section("Details") { TextField("Title", text: $production.name) } Section("Characters") { List(filteredCharacters) { character in Text(character.name) } HStack { TextField("Character", text: $characterName) Button("Add") { let newCharacter = Character(name: characterName, production: production) modelContext.insert(newCharacter) characterName = "" } .disabled(characterName.isEmpty) } if !filteredCharacters.isEmpty { Picker("Select your role", selection: $selectedCharacter) { Text("Select") .tag(nil as Character?) ForEach(filteredCharacters) { character in Text(character.name) .tag(character as Character?) } } .pickerStyle(.menu) } } } .toolbar { Button("Save") { //Fatal error: Duplicate keys of type 'AnyHashable' were found in a Dictionary. This usually means either that the type violates Hashable's requirements, or that members of such a dictionary were mutated after insertion. if let selectedCharacter = selectedCharacter { selectedCharacter.myCharacter = true } modelContext.insert(production) do { try modelContext.save() } catch { print("Failed to save context: \(error)") } dismiss() } .disabled(production.name.isEmpty || selectedCharacter == nil) } } } }
2
0
266
2w
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
219
2w
swiftdata model polymorphism?
I have a SwiftData model where I need to customize behavior based on the value of a property (connectorType). Here’s a simplified version of my model: @Model public final class ConnectorModel { public var connectorType: String ... func doSomethingDifferentForEveryConnectorType() { ... } } I’d like to implement doSomethingDifferentForEveryConnectorType in a way that allows the behavior to vary depending on connectorType, and I want to follow best practices for scalability and maintainability. I’ve come up with three potential solutions, each with pros and cons, and I’d love to hear your thoughts on which one makes the most sense or if there’s a better approach: **Option 1: Use switch Statements ** func doSomethingDifferentForEveryConnectorType() { switch connectorType { case "HTTP": // HTTP-specific logic case "WebSocket": // WebSocket-specific logic default: // Fallback logic } } Pros: Simple to implement and keeps the SwiftData model observable by SwiftUI without any additional wrapping. Cons: If more behaviors or methods are added, the code could become messy and harder to maintain. **Option 2: Use a Wrapper with Inheritance around swiftdata model ** @Observable class ParentConnector { var connectorModel: ConnectorModel init(connectorModel: ConnectorModel) { self.connectorModel = connectorModel } func doSomethingDifferentForEveryConnectorType() { fatalError("Not implemented") } } @Observable class HTTPConnector: ParentConnector { override func doSomethingDifferentForEveryConnectorType() { // HTTP-specific logic } } Pros: Logic for each connector type is cleanly organized in subclasses, making it easy to extend and maintain. Cons: Requires introducing additional observable classes, which could add unnecessary complexity. **Option 3: Use a @Transient class that customizes behavior ** protocol ConnectorProtocol { func doSomethingDifferentForEveryConnectorType(connectorModel: ConnectorModel) } class HTTPConnectorImplementation: ConnectorProtocol { func doSomethingDifferentForEveryConnectorType(connectorModel: ConnectorModel) { // HTTP-specific logic } } Then add this to the model: @Model public final class ConnectorModel { public var connectorType: String @Transient public var connectorImplementation: ConnectorProtocol? // Or alternatively from swiftui I could call myModel.connectorImplementation.doSomethingDifferentForEveryConnectorType() to avoid this wrapper func doSomethingDifferentForEveryConnectorType() { connectorImplementation?.doSomethingDifferentForEveryConnectorType(connectorModel: self) } } Pros: Decouples model logic from connector-specific behavior. Avoids creating additional observable classes and allows for easy extension. Cons: Requires explicitly passing the model to the protocol implementation, and setup for determining the correct implementation needs to be handled elsewhere. My Questions Which approach aligns best with SwiftData and SwiftUI best practices, especially for scalable and maintainable apps? Are there better alternatives that I haven’t considered? If Option 3 (protocol with dependency injection) is preferred, what’s the best way to a)manage the transient property 2) set the correct implementation and 3) pass reference to swiftdata model? Thanks in advance for your advice!
0
0
154
2w
Can't access child entries of SwiftData class
When I tried to use a working project with iOS 18 installed on my device, it wouldn't work anymore and crash right away. Before with iOS 17 it was working fine. I can't access child variables that are saved in an Array in a parent object in SwiftData. The error is always somewhere in these hidden lines: { @storageRestrictions(accesses: _$backingData, initializes: _title) init(initialValue) { _$backingData.setValue(forKey: \.title, to: initialValue) _title = _SwiftDataNoType() } get { _$observationRegistrar.access(self, keyPath: \.title) return self.getValue(forKey: \.title) } set { _$observationRegistrar.withMutation(of: self, keyPath: \.title) { self.setValue(forKey: \.title, to: newValue) } } } The child classes are also inserted and saved into the modelContext when created and set to the parent instance, but I also can't fetch them via modelContext.fetch() - Error here is: Thread 1: EXC_BREAKPOINT (code=1, subcode=0x243a62a4c) Maybe there is a problem with the relationship between two saved instances. The parent instances are saved correctly and it was working in iOS 17. The problem is similar to these two cases: https://forums.developer.apple.com/forums/thread/762679 https://forums.developer.apple.com/forums/thread/738983 I changed the logic after I reviewed these threads, as I am now linking the parent and child instances, that got rid of one warning in the console. button.canvas = canvas modelContext.insert(button) canvas.buttons = [button] But in the end those threads were not enough for me to find a fix for my problem. A small project can be found here: https://github.com/DonMalte/SwiftDataTest
3
0
305
2w
CloudKit sync stopped working with error „You can't save and delete the same record"
Hi there We're using CloudKit in our app which, generally, syncs data perfectly between devices. However, recently the sync has stopped working (some changes will never sync and the sync is delayed for several days even with the app open on all devices). CloudKit's logs show the error „You can't save and delete the same record" and „Already have a mirrored relationship registered for this key", etc. We’ve a hunch that this issue is related to a mirrored relationship of one database entity. Our scenario: We've subclassed the database entities. The database model (which we can't share publicly) contains mirrored relationships. We store very long texts in the database (similar to a Word document that contains markup data – in case that’s relevant). Deleting all data and starting with a completely new container and bundle identifier didn’t help (we tried that multiple times). This issue occurs on macOS (15.2(24C101) as well on iOS (18.2). Any hints on how to get the sync working again? Should we simply avoid mirrored relationships? Many thanks
3
0
264
2w
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
209
2w
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
259
3w
How to let iCloud sync across the devices without launching the app at midnight?
Hi, I have designed an app which needs to reschedule notifications according to the user's calendar at midnight. The function has been implemented successfully via backgroundtask. But since the app has enabled iCloud sync, some users will edit their calendar on their iPad and expect that the notifications will be sent promptly to them on iPhone without launching the app on their iPhone. But the problem is that if they haven't launched the app on their iPhone, iCloud sync won't happen. The notifications on their iPhone haven't been updated and will be sent wrongly. How can I design some codes to let iCloud sync across the devices without launching the app at midnight and then reschedule notifications?
4
0
322
3w
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.
12
0
580
3w
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
319
3w
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
238
3w
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
367
3w
SwiftData crashes after updating to MacOS 15.2
After updating to 15.2 I am seeing frequent crashes in my in-development app related to SwiftData. For instance, I have a 100% reproducible crash when I make the app lose and regain focus. There is also a crash that seem to be triggered by a modelContext.save() call in one of my ModelActors. With both of these crashes, the issue seems to be around keeping SwiftData models up to date. The first item in the stacktrace that is not machinecode is always some getter on a SwiftData collection or object. In the console, these crashes are accompanied by output along the lines of: === AttributeGraph: cycle detected through attribute 820680 === precondition failure: setting value during update: 930592 error: the replacement path doesn't exist: "/var/folders/b7/0dw7ztp13fgfxlj19by851tw0000gn/T/swift-generated-sources/@__swiftmacro_10SpaceDebug8TodoListV5todos33_5575DE008494C519BB9FA49C405133E1LL5QueryfMa_.swift" error: the replacement path doesn't exist: "/var/folders/b7/0dw7ztp13fgfxlj19by851tw0000gn/T/swift-generated-sources/@__swiftmacro_10SpaceDebug8TodoListV5todos33_5575DE008494C519BB9FA49C405133E1LL5QueryfMa_.swift" Can't show file for stack frame : <DBGLLDBStackFrame: 0x35a57c4e0> - stackNumber:27 - name:TodoList.todos.getter. The file path does not exist on the file system: /var/folders/b7/0dw7ztp13fgfxlj19by851tw0000gn/T/swift-generated-sources/@__swiftmacro_10SpaceDebug8TodoListV5todos33_5575DE008494C519BB9FA49C405133E1LL5QueryfMa_.swiftCan't show file for stack frame : <DBGLLDBStackFrame: 0x35a57c4e0> - stackNumber:27 - name:TodoList.todos.getter. The file path does not exist on the file system: /var/folders/b7/0dw7ztp13fgfxlj19by851tw0000gn/T/swift-generated-sources/@__swiftmacro_10SpaceDebug8TodoListV5todos33_5575DE008494C519BB9FA49C405133E1LL5QueryfMa_.swiftCan't show file for stack frame : <DBGLLDBStackFrame: 0x35a5a82f0> - stackNumber:62 - name:TodoList.todos.getter. The file path does not exist on the file system: /var/folders/b7/0dw7ztp13fgfxlj19by851tw0000gn/T/swift-generated-sources/@__swiftmacro_10SpaceDebug8TodoListV5todos33_5575DE008494C519BB9FA49C405133E1LL5QueryfMa_.swift Has anyone run into something similar? I'm looking for suggestions on how to debug this. Cheers, Bastiaan
2
0
274
3w
CKSyncEngine API design problems and maintenance status inside Apple?
Something I want to know and all users of CKSyncEngine care about I'm going to build a full stack solution using CKSyncEngine, but what's the near future and the support and maintenance priorities inside Apple for CKSyncEngine? There is only one short video for CKSyncEngine, in 2023, no updates after that, no future plans mentioned. I'm worried that this technology be deprecated or not activity maintained. This is a complex technology, without being activity maintained (or open-sourced) there will be fatal production issues we the developer cannot solve. The CK developer in the video stated that "many apps" were using the framework, but he did not list any. The only named is NSUbiquitousKeyValueStore, but NSUbiquitousKeyValueStore is too simple a use case. I wonder is apple's Notes.app using it, or going to use it? Is SwiftData using it? API Problems The API design seems a little bit tricky, not designed from a user's perspective. handleEvent doesn't contain any context information about which batch. How do I react the event properly? Let's say our sync code and CKSyncEngine, and callbacks are all on a dedicated thread. Consider this: in nextRecordZoneChangeBatch you provided a batch of changes, let's call this BATCH 1, including an item in database with uuid "***" and name "yyy" before the changes are uploaded, there are new changes from many OTHER BACKGROUND THREADS made to the database. item "***"'s name is now "zzz" handle SentRecordZoneChanges event: I get records that uploaded or failed, but I don't know which BATCH the records belong to. How do I decide if i have to mark "***" as finished uploading or not? If I mark *** as finished that's wrong, the new name "zzz" is not uploaded. I have to compare every field of *** with the savedRecord to decide if I finished uploading or not? That is not acceptable as the performance and memory will be bad. Other questions I have to add recordIDs to state, and wait for the engine to react. I don't think this is a good idea, because recordID is a CloudKit concept, and what I want to sync is a local database. I don't see any rational for this, or not documented. If the engine is going to ask for a batch of records, you can get all record ids from the batch?
9
0
458
3w
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
347
3w
Develop a piece of code to force iCloud Drive sync
Hello, I apologize if this post could be slightly out of forum topic but I have one issue that I cannot solve. I tried a few times to call Apple support but the only indication that have given to me is to try with this forum. The issue I have is simple. Sometimes the modifications performed on iCloud Drive on one computer are not properly synced between the local folder /Users/[username]/Library/Mobile Documents/... and the cloud and therefore are not shared across all devices that use the same iCloud Drive. This is very disturbing as it may lead to a data loss. I would like to write a simple software that activates the iCloud Drive sync between the local iCloud folder /Users/[username]/Library/Mobile Documents/... and the Cloud. A simple macOS bash script would be fine but also other pieces of software are welcome. Can anyone please help me? Thanks! Daniele
1
0
262
Dec ’24
NSPersistentCloudKitContainer Import failed (incomprehensible archive)
I am using NSPersistentCloudKitContainer and I decided to add a property to an entity. I accidentally ran try! container.initializeCloudKitSchema(options: []) while using the production container in Xcode (com.apple.developer.icloud-container-environment) which throw a couple of errors and created some FAKE_ records in my production container. So I changed to my development container and ran the try! container.initializeCloudKitSchema(options: []) and now it succeeded. After that I cleaned up the FAKE_ records scattered in production container but in Xcode when I'm running I now get these logs in the console (and I can't seem to get rid of them): error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _importFinishedWithResult:importer:](1398): <PFCloudKitImporter: 0x300cc72c0>: Import failed with 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)} error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate recoverFromError:](2310): <NSCloudKitMirroringDelegate: 0x302695770> - Attempting recovery from 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)} error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _recoverFromError:withZoneIDs:forStore:inMonitor:](2620): <NSCloudKitMirroringDelegate: 0x302695770> - Failed to recover from error: NSCocoaErrorDomain:4864 Recovery encountered the following error: (null):0 error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate resetAfterError:andKeepContainer:](610): <NSCloudKitMirroringDelegate: 0x302695770> - resetting internal state after 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)} error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _requestAbortedNotInitialized:](2198): <NSCloudKitMirroringDelegate: 0x302695770> - Never successfully initialized and cannot execute request '<NSCloudKitMirroringExportRequest: 0x303a52d00> 548CB420-E378-42E5-9607-D23E7A2A364D' 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)}
2
0
262
Dec ’24