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.

CloudKit Documentation

Posts under CloudKit tag

249 Posts
Sort by:
Post not yet marked as solved
1 Replies
1.7k Views
I followed along apples Article for relevant store changes, mainly for data deduplication. https://developer.apple.com/documentation/coredata/consuming_relevant_store_changes I also downloaded the Core Data / CloudKit Demo App which already has a deduplication process. https://developer.apple.com/documentation/coredata/synchronizing_a_local_store_to_the_cloud In the Demo project I observed that more often than not, Posts loose their relationship to Tags. After some investigation I assume that this happens, when a Tag which has a relationship to a Post, gets deleted during the deduplication process, before the relevant Post was synced to the device. When the Post now arrives on the device, its related Tag Object does no longer exist. Therefore it's also not possible to find the retained, deduped Tag-Object which should be connected to the Post. I'm wondering why this was implemented that way in the Demo Project, as this really causes critical data loss. I have also no Idea how to avoid it. In the Article, Apple recommends to use Core Datas tombstone to preserve some values of deleted objects. However, there is no further explaination. It's also not implemented in the Demo project. How do I restore lost relationships and how does the tombstone help with it? Example: Before it synced: After it synced:
Posted
by
Post marked as solved
3 Replies
1.8k Views
I'm using Xcode 14 beta 4, on macOS Monterey 12.5, developing a Mac app that's using CoreData CloudKit sync — with my context being configured with two configurations (one for a local cache and one data synced via CloudKit). An issue recently appeared where the app crashes soon after start-up with this message: [threadmgrsupport] _TSGetMainThread_block_invoke:Main thread potentially initialized incorrectly, cf <rdar://problem/67741850> And this stack trace: Thread 1 Queue : com.apple.main-thread (serial) #0 0x000000018b86b5e8 in ___NSAssertMainEventQueueIsCurrentEventQueue_block_invoke () #1 0x0000000105b563a8 in _dispatch_client_callout () #2 0x0000000105b58300 in _dispatch_once_callout () #3 0x000000018b86a2dc in _DPSNextEvent () #4 0x000000018b868e14 in -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] () #5 0x000000018b85afe0 in -[NSApplication run] () #6 0x000000018b82c6fc in NSApplicationMain () #7 0x00000001ae281e98 in specialized runApp(_:) () #8 0x00000001aee10588 in runApp<τ_0_0>(_:) () #9 0x00000001ae88626c in static App.main() () Things work again, if I disable the CloudKit sync by not setting cloudKitContainerOptions on my "Cloud" configuration. Similarly, it works on first install, but reappears on subsequent runs. The code is in a package that's shared with an iOS version of the app, which has no such issues. I also tried going back to previous commits that worked before, and it works again until at some point it stops working again for the same commits. So it doesn't seem to be caused directly by my code, but rather by something that the CloudKit sync is doing. Any help would be much appreciated.
Posted
by
Post marked as solved
4 Replies
1.1k Views
Before the code... CloudKit, background mode (remote notifications) and push notifications are added to Capabilities. Background sync is working fine and view loads current store on manual fetch. Code that initialises the persistent container in app delegate... - (NSPersistentCloudKitContainer *)persistentContainer {     // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.     @synchronized (self) {         if (_persistentContainer == nil) {             _persistentContainer = [[NSPersistentCloudKitContainer alloc] initWithName:@"Expenses"];             [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {                 if (error != nil) {                     __block NSPersistentStoreDescription *sDescription = storeDescription;                     dispatch_async(dispatch_get_main_queue(), ^(){                         [sDescription setOption:[NSNumber numberWithBool:YES] forKey:@"PersistentHistoryTracking"];                         [sDescription setOption:[NSNumber numberWithBool:YES] forKey:@"NSPersistentStoreRemoteChangeNotificationOptionKey"];                     }); #ifdef DEBUG                     NSLog(@"Unresolved error %@, %@", error, error.userInfo); #endif                     abort();                 }                 else #ifdef DEBUG                     NSLog(@"Store successfully initialized"); #endif             }];         }     }     return _persistentContainer; } In Home view controller which is the initial view controller i am adding an observer for the remote notification...     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadViewONCKChangeNotification) name:NSPersistentStoreRemoteChangeNotification object:[appDelegate.persistentContainer persistentStoreCoordinator]]; I am not receiving any store change notifications. Have added breakpoints to see if selector is fired. no go. CloudKit Console also doesn't show any pushes for the concerned time period.
Posted
by
Post not yet marked as solved
5 Replies
4.1k Views
I've found old forum posts that reference CloudKit pricing based on usage (after exceeding the 'Free' tier). However, it doesn't seem that Apple has any information on any of their website that indicate what that pricing is, or otherwise the limits of a free tier. The closest I've found to this is on https://developer.apple.com/icloud/cloudkit/ where it says, "Store private data securely in your users’ iCloud accounts for limitless scale as your user base grows, and get up to 1PB of storage for your app’s public data." So does this mean that the only CloudKit limits now are: Private data: dependent on individual user's remaining iCloud storage space Public data: 1 PB Request count/day: unlimited Download usage/day: unlimited I'm being a little sarcastic, but at the same time, if there are still limits and a pricing structure, I'm really scratching my head as to why that doesn't seem to be published anywhere. Ultimately, I'm trying to find the best, reliable public asset storage with cross-device usage (iOS, tvOS) solution and am weighing CloudKit versus other cloud storage solutions and their costs. Side note: I'm kinda confused why CloudKit provides public asset storage in the first place, since I thought On-Demand Resources was intended to fill that gap (and ODR does have storage limits too).
Posted
by
Post marked as solved
2 Replies
1.8k Views
I'm building a macOS + iOS SwiftUI app using Xcode 14.1b3 on a Mac running macOS 13.b11. The app uses Core Data + CloudKit. With development builds, CloudKit integration works on the Mac app and the iOS app. Existing records are fetched from iCloud, and new records are uploaded to iCloud. Everybody's happy. With TestFlight builds, the iOS app has no problems. But CloudKit integration isn't working in the Mac app at all. No existing records are fetched, no new records are uploaded. In the Console, I see this message: error: CoreData+CloudKit: Failed to set up CloudKit integration for store: <NSSQLCore: 0x1324079e0> (URL: <local file url>) Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.cloudd was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.cloudd was invalidated: failed at lookup with error 159 - Sandbox restriction.} I thought it might be that I was missing the com.apple.security.network.client entitlement, but adding that didn't help. Any suggestions what I might be missing? (It's my first sandboxed Mac app, so it might be really obvious to anyone but me.)
Posted
by
Post marked as solved
1 Replies
901 Views
Hello, I've created multiple Entity in CoreData, that has a relationship to one another. However, I'm unable to create @discardableResult to use in SwiftUI preview. /// Entity data for use with canvas previews. static var preview: Entity1 {         let entities1 = Entity1.makePreviews(count: 1)         return entities1[0] } @discardableResult static func makePreviews(count: Int) -&gt; [Entity1] {         var contents = [Entity1]()         let viewContext = PersistenceController.preview.container.viewContext         let persistenceController = PersistenceController.shared         for index in 0..&lt;count {             let entities1 = Entity1(context: viewContext)             entities1.id = UUID()             entities1.title = "Amazing day!"             let photo = Photo(context: viewContext)             let imageData = UIImage(named: "Golden Temple")?.jpegData(compressionQuality: 1) ?? Data()             photo.linkedToJournal = journal             let thumbnail = Thumbnail(context: viewContext)             let thumbnailData = persistenceController.thumbnail(with: imageData)?.jpegData(compressionQuality: 1)             thumbnail.data = thumbnailData             thumbnail.photo = photo             let photoDataObject = PhotoData(context: viewContext)             photoDataObject.data = imageData             photoDataObject.photo = photo             contents.append(entities1)         }         return contents } You may also try to use the sample code from https://developer.apple.com/documentation/coredata/sharing_core_data_objects_between_icloud_users to build a SwiftUI Preview. Appreciate if you could suggest how to build a SwiftUI preview as it saves a lot of development effort and time. Thank you very much!
Posted
by
Post not yet marked as solved
3 Replies
1.3k Views
I have a CoreData model, in a Swift Package with tests. I can successfully run the tests, when I load the model using NSPersistentContainer, however attempting this with NSPersistentCloudKitContainer always fails in the call to loadPersistentStores(completionHandler block: @escaping (NSPersistentStoreDescription, Error?) -> Void) The error is : [CK] BUG IN CLIENT OF CLOUDKIT: Not entitled to listen to push notifications. Please add the 'aps-connection-initiate' entitlement. This issue is described on StackOverflow however, the accepted solution does not appear to work in my case. I have tried adding the aps-connection-initiate key to my App Info.plist, the Test Info.plist and the SPM bundle. No change. (NB. adding this to the entitlements file just breaks auto signing). I have enabled App entitlements for App Groups, Remote Notifications background mode, Push Notifications and iCloud CloudKit with a store identifier. I have checked my model. All relationships have inverses. No unique constraints, etc. etc. I am sharing a Bundle ID with a previous version of the App, that also uses CoreData+CloudKit, each version has it's own Model and container identifier, each container identifier is available in the provisioning profile. The new version of the model has two NSPersistentStoreDescriptions, one is configured for CloudKit, the other is a local cache. I am completely stuck, suggestions would be very welcome.
Posted
by
Post not yet marked as solved
1 Replies
1.8k Views
#1 As a new starter, I just created a new sample app in Xcode and added iCloud capability. On the CloudKit dashboard I do see the container but selecting the specific container shows the following message in red "Error loading container details." #2 I was able to create a new RecortType via the cloud kit dashboard UI but when I try to create a record form the dashboard UI somehow it does not let me select the record type of the record (I see it in the list but its grayed out). I am not sure what the reason for #1 and #2 and if the two issues are related. Could not find any help online. I am trying to create an app directly with cloudKit and Javascript (not a companion IOS app). Any help would
Posted
by
Post not yet marked as solved
1 Replies
957 Views
I'm working on a Core Data / CloudKit public Database. Apple recommends not to delete the object but to set a variable e.g. isTrashed to true. After that a predicate should be set for the FetchRequest so that this object is no longer displayed. So in my view I set this variable to true when an object is deleted and this is also set correctly. Here is the query directly from the dashboard: Unfortunately the predicate doesn't work as it should and the object is still displayed. Can anyone tell me what I am doing wrong? Fetch Request static var productsByName: NSFetchRequest<Product> { /// create Request let request: NSFetchRequest<Product> = Product.fetchRequest() /// sortDescriptor request.predicate = NSPredicate(format: "isTrashed = false") // <-- predicate for isTrashed request.sortDescriptors = [NSSortDescriptor(keyPath: \Product.name, ascending: true)] return request } ContentView.swift struct ContentView: View { @SectionedFetchRequest(fetchRequest: ContentView.productsByName, sectionIdentifier: \Product.manufacturer?.name) var products: SectionedFetchResults<String?, Product> var body: some View { NavigationStack { List { ForEach(products) { section in Section(header: Text(section.id ?? "unassigned")) { ForEach(section) { product in NavigationLink(destination: productDetailView(product: product)){ Text(product.name ?? "na") } } .onDelete { rows in for row in rows { let product = section[row] if storageProvider.persistentContainer.canDeleteRecord(forManagedObjectWith: product.objectID) { storageProvider.deleteProduct(product) } else { product.isTrashed = true // <-- here the value for isTrashed is set do { try storageProvider.persistentContainer.viewContext.save() } catch { storageProvider.persistentContainer.viewContext.rollback() print("Failed to save context: \(error)") } } } } } } } } } } info 1 additional info: I added this code to the detailView of the products to check if the value is set correct: Text("is trashed: \(product.isTrashed ? "true" : "false")") ... and yes it is: info 2 I also tried these for the query: request.predicate = NSPredicate(format: "isTrashed = 0") request.predicate = NSPredicate(format: "isTrashed = FALSE") request.predicate = NSPredicate(format: "isTrashed = NO") request.predicate = NSPredicate(format: "isTrashed = 0") request.predicate = NSPredicate(format: "isTrashed == FALSE") request.predicate = NSPredicate(format: "isTrashed == NO") request.predicate = NSPredicate(format: "%K = %@", argumentArray: [#keyPath(Product.isTrashed), false]) request.predicate = NSPredicate(format: "%K == %@", argumentArray: [#keyPath(Product.isTrashed), false]) So I don't think the query itself is the problem :/ info 3 but for example this predicate directly on the view is working: .onReceive(productName.$debounced) { query in /// don't filter when searchbar is empty guard !query.isEmpty else { products.nsPredicate = nil return } /// set filter when someone searches products.nsPredicate = NSPredicate(format: "%K CONTAINS[cd] %@", argumentArray: [#keyPath(Product.name), query]) } That's why I don't understand why the predicate on the FetchRequest isn't working. Does anyone have an idea?
Posted
by
Post not yet marked as solved
3 Replies
679 Views
I have some code from a youtube video that I have completed before, but now when I scroll up, xCode crashes. I have a class with an enum. Sticky headers are there, then as i scroll down, the headers disappear. Then as a // MARK: comes up, we crash. I tried changing the MARK so that it was not bolded, but it still crashes. Is there a setting to disable sticky headers? This was happening in xCode 14.2, and i upgraded, to 14.3, and it went away for a while, but now the problem is back, well intermittently. I did a Clean Build Folder and a Clear All Issues. Still annoying.
Posted
by
Post marked as solved
3 Replies
1.1k Views
I have an iPhone app the uses CloudKit for Core Data syncing. I also have a companion Apple Watch app that syncs to the same CloudKit records. The watch can be used without the iPhone app as well but they both independently sync to the same CloudKit database. This works reasonably well. As soon as either app is opened, the CloudKit will pull down the latest records. I'd like to add a watch complication that shows the state of the CloudKit records. I supported this by adding a Widget extension, embedded in my watch app. The Core Data database in the watch app is part of an app group, so the complication is able to query the same database. So far so good. I'm running into problems with the complication updating after remote records are changed from the iPhone. Here is what is happening: When records are changed on the iPhone, the data syncs to CloudKit but the watch app is not updated when in the background. This is noticed when you open the app and it takes a second for the view to show the new records. Since Core Data database on the watch is not being updated while in the background, the complication is not being updated at all. Part of my confusion is I assumed CloudKit was meant to make this more seamless with silent push notifications? I have the "Remote Notifications" capability enabled on my WatchApp. It seems that only works while the app is in the foreground though. This seems very limiting when you have a complication that depends on the Watch app's Core Data state. I have a few things to work around this with mixed success: "Wake" the watch app explicitly when records are changed on the iPhone app using WatchConnectivityManager. The hope is that by waking the watch app, it will sync with iCloud. This either isn't working or intermittenly works. It is also not clear to me that by activating the watch app, that it will trigger records to sync. I wish there were a way to ask Core Data to sync explicitly. Whenever the Apple watch app wakes in the last step, ask it to WidgetCenter to reload the widget. This process feels convoluted and seems to negate some of the the benefits of CloudKit to synchronize data which I thought would be baked into this process. Any thoughts on a better approach to all this?
Posted
by
Post marked as solved
3 Replies
547 Views
I have an app with a CloudKit Public Database in which a CKRecord can contain a CKAsset or two that holds the url of image data. I don't want to always obtain the image data so my desiredKeys excludes the CKAsset key in the CKRecord in that case. I use the following Swift function. var (matchResults, queryCursor) = try await database.records(matching: query, desiredKeys: desiredKeys) The desiredKeys variable could be an array of strings with the keys of CKRecord fields I want to return or nil if I want all of the data including the asset data. After I have the records, I do the following. if let imageAsset = record["ImageAsset"] as? CKAsset, let url = imageAsset.fileURL, let data = try? Data(contentsOf: url) { self.imageData = data } However, when I exclude the "ImageAsset" key from the desiredKeys array, my if let imageAsset contains the asset information. Looking at the received data, I can see that other keys that I exclude are not being downloaded, but the CKAsset url appears to be downloaded. Why? I expected that the if let would have been nil and the code within the if let would not have been executed.
Posted
by
Post not yet marked as solved
0 Replies
616 Views
I'm using NSPersistentCloudKitContainer together with a private and public database. I have a public database with articles. Users should be able to like an article but I'm wondering what would be the best design approach to achieve this. The users can also add articles that they find online which are then automatically liked for the user adding it (and uploaded to the public database) Question 1 I want you to be able to see how many people have liked an article, so I think there will perhaps be an array on the article with the userId who liked it and then you just do a count on it? Or do you think there is a better way? Question 2 I am thinking about how the liked article should be "saved" for the user, either put that article in their private database, but then that article will be disconnected from the public article. Or I can filter out among the public articles that contain the user's userId (however, I'm a little unsure how it works in practice as the public database is polled every 30 minutes with NSPersistentCloudKitContainer) and when the user adds an article from some website then he wants that article to appear directly in the app.
Posted
by
Post not yet marked as solved
2 Replies
1.5k Views
Can someone please shed some light? I have an app that uses Core Data and CloudKit, up until the last version, I was able to sync data between devices but now after I added two new Entities for some reason it stopped syncing between devices. Here is how I did the change: Created a new Core Data container. Added the new Entities and their Attributes Tested the new Entities locally to be able to send the new schema to CloudKit. Went to CloudKit and made sure that the new Entities and Attributes were reflected on the Developent database. Deploy Schema Cahnges. Went to the Production database to make sure the new schema was deployed; and it was, both databases look the same. Testing: Tested in the simulator and with a real device and everything syncs, even the new Entities. If I download the app from the App Store on two different devices they do NOT sync. Based on the procedure I'm describing above, is there any important step I may have missed when doing the migration? I'm not sure if this is related to the syncing issue but after testing a few times, I no longer can turn the iCloud on, I get the following message when I try to turn iCloud Sync On. CoreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate resetAfterError:andKeepContainer:]: <NSCloudKitMirroringDelegate: 0x282c488c0> - resetting internal state after error: Error Domain=NSCocoaErrorDomain Code=134410 "CloudKit setup failed because there is another instance of this persistent store actively syncing with CloudKit in this process." UserInfo={NSURL=file:///var/mobile/Containers/Data/Application/73F19BC7-4538-4098-85C7-484B36192CF3/Library/Application%20Support/CoreDataContainer.sqlite, NSLocalizedFailureReason=CloudKit setup failed because there is another instance of this persistent store actively syncing with CloudKit in this process., NSUnderlyingException=Illegal attempt to register a second handler for activity identifier com.apple.coredata.cloudkit.activity.setup.8D4C04F6-8040-445A-9447-E5646484521} Any idea of what could be wrong and preventing the devices from syncing? Any idea or suggestion is welcome. Thanks
Posted
by
Post not yet marked as solved
1 Replies
526 Views
Hi, My macOS app's production build is crashing on start with an unhelpful crashdump. In the console, the only error in the Console is BUG IN CLIENT OF CLOUDKIT: Not entitled to listen to push notifications. Please add the 'com.apple.private.aps-connection-initiate' entitlement. Adding this entitlement to my entitlements.plist breaks the app entirely (Unsatisfied entitlements). Here is how I'm loading my persisten store: lazy var persistentContainer: NSPersistentCloudKitContainer = { let container = NSPersistentCloudKitContainer(name: "ChatModel") guard let description = container.persistentStoreDescriptions.first else { fatalError("###\(#function): Failed to retrieve a persistent store description.") } if(UserDefaults.standard.bool(forKey: StoredPreferenceKey.iCloudSync)){ description.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.XXXXX") } else { description.cloudKitContainerOptions = nil } description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) /* #if DEBUG do { // Use the container to initialize the development schema. try container.initializeCloudKitSchema(options: []) } catch { // Handle any errors. } #endif */ container.loadPersistentStores { description, error in if let error = error { fatalError("Unable to load persistent stores: \(error)") } } container.viewContext.automaticallyMergesChangesFromParent = true return container }() I've set up Core Data + CloudKit following the official docs, screenshots attached. The app works fine in development mode. I'm using Xcode 14.3, and I've tried with Xcode 14.2 too. Any idea ? Web results (i.e. only two relevant threads) bring no answer.
Posted
by
Post marked as solved
2 Replies
554 Views
I'm using NSPersistentCloudKitContainer and I'm getting warnings in the console saying: CoreData: CloudKit: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _scheduleAutomatedExportWithLabel:activity:completionHandler:]_block_invoke(3457): <NSCloudKitMirroringDelegate: 0x2831e40e0> - Finished automatic export - AppActivationExport - with result: <NSCloudKitMirroringResult: 0x280695d70> storeIdentifier: F2C60E7A-CEC4-44F2-B467-7324C065AD33 success: 0 madeChanges: 0 error: Error Domain=NSCocoaErrorDomain Code=134406 "Request '1FA53D40-43FB-4751-8719-0D26393D5301' was aborted because the mirroring delegate never successfully initialized due to error: <CKError 0x2806798c0: "Invalid Arguments" (12/2016); server message = "Field '___modTime' is not marked sortable"; op = DC861AAA03EBFBF0; uuid = 37A8231D-AB96-4B7C-8132-****9A0C1D39; container ID = "iCloud.com.***">" UserInfo={NSLocalizedFailureReason=Request '1FA53D40-43FB-4751-8719-0D26393D5301' was aborted because the mirroring delegate never successfully initialized due to error: <CKError 0x2806798c0: "Invalid Arguments" (12/2016); server message = "Field '___modTime' is not marked sortable"; op = DC861AAA03EBFBF0; uuid = 37A8231D-AB96-4B7C-8132-****9A0C1D39; container ID = "iCloud.com.***">} I have added indexes for recordName and modifiedTimestamp to all my records as queryable as per the instructions.
Posted
by
Post not yet marked as solved
0 Replies
493 Views
In the following code, I'm saving and syncing objects in Core Data and CloudKit, everything is working fine, once the user creates some objects, the data starts syncing as soon as the user turns the Toggle switch On in the SettingsView. The issue I'm having is that the data continue syncing even after the switch is turned Off until I kill and relaunch the app. After relaunching the app, the data stops syncing. Any idea what could I do to make sure that the data stops syncing as soon as the toggle switch is turned off? Again, everything would work fine if the user would kill and relaunch the app right after turning it off, the data stops syncing. I thought that by calling carViewModel.updateCloudKitContainer() right after turning it off would do the trick since I'm disabling the CloudKit container by making it nil, description.cloudKitContainerOptions = nil but obviously is not enough. Core Data Manager class CoreDataManager{ // Singleton static let instance = CoreDataManager() @AppStorage(UserDefaults.Keys.iCloudSyncKey) private var iCloudSync = false static var preview: CoreDataManager = { // Create preview objects do { try viewContext.save() } catch { } return result }() lazy var context: NSManagedObjectContext = { return container.viewContext }() lazy var container: NSPersistentContainer = { return setupContainer() }() init(inMemory: Bool = false){ /// for preview purposes only, remove if no previews are needed. if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") } } func setupContainer()->NSPersistentContainer{ print("Assgning persistent container... ") let container = NSPersistentCloudKitContainer(name: "CoreDataContainer") guard let description = container.persistentStoreDescriptions.first else{ fatalError("###\(#function): Failed to retrieve a persistent store description.") } description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) if iCloudSync{ let cloudKitContainerIdentifier = "iCloud.com.sitename.myApp" let options = NSPersistentCloudKitContainerOptions(containerIdentifier: cloudKitContainerIdentifier) description.cloudKitContainerOptions = options }else{ description.cloudKitContainerOptions = nil // turn cloud sync off } container.loadPersistentStores { (description, error) in if let error = error{ print("Error loading Core Data. \(error)") } } container.viewContext.automaticallyMergesChangesFromParent = true container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy return container } func save(){ do{ try context.save() }catch let error{ print("Error saving Core Data. \(error.localizedDescription)") } } } View Model class CarViewModel: ObservableObject{ let manager: CoreDataManager @Published var cars: [Car] = [] init(coreDataManager: CoreDataManager = .instance){ self.manager = coreDataManager loadCars() } func updateCloudKitContainer(){ manager.container = manager.setupContainer() } func addCar(model:String, make:String?){ // create car save() loadCars() } func deleteCar(car: Car){ // delete car save() loadCars() } func loadCars(){ let request = NSFetchRequest<Car>(entityName: "Car") let sort = NSSortDescriptor(keyPath: \Car.model, ascending: true) request.sortDescriptors = [sort] do{ cars = try manager.context.fetch(request) }catch let error{ print("Error fetching businesses. \(error.localizedDescription)") } } func save(){ self.manager.save() } } Settings View to Turn ClouldKit ON and OFF struct SettingsView: View { @ObservedObject var carViewModel:CarViewModel @AppStorage(UserDefaults.Keys.iCloudSyncKey) private var iCloudSync = false var body: some View { VStack{ Toggle(isOn: $iCloudSync){// turns On and Off sync HStack{ Image(systemName: iCloudSync ? "arrow.counterclockwise.icloud" : "lock.icloud") .foregroundColor(Color.fsRed) Text(" iCloud Sync") } } .tint(Color.fsRed) .onChange(of: iCloudSync){ isSwitchOn in if isSwitchOn{ iCloudSync = true carViewModel.updateCloudKitContainer() }else{ iCloudSync = false // turn Off iCloud Sync carViewModel.updateCloudKitContainer() } } } } } Display Cars View struct CarsView: View { @ObservedObject var carViewModel:CarViewModel // Capture NOTIFICATION var didRemoteChange = NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange).receive(on: RunLoop.main) var body: some View { NavigationView{ VStack{ List { ForEach(carViewModel.cars) { car in HStack{ VStack(alignment:.leading){ Text(car.model ?? "") .font(.title2) Text(car.make ?? "") .font(.callout) } } .swipeActions { Button( role: .destructive){ deleteCar = car showDeleteActionSheet = true }label:{ Label("Delete", systemImage: "trash.fill") } } } } .navigationBarTitle("Cars") .onAppear{ carViewModel.loadCars() } // reload cars on NOTIFICATION .onReceive(self.didRemoteChange){ _ in carViewModel.loadCars() } } } } }
Posted
by
Post not yet marked as solved
0 Replies
589 Views
Building an app with iCloudKit integration. Build is successful but Simulator crashes with above error. I have an active developer account, have configured the app for iCloudKit integration in Signing and Capabilities, have logged into Xcode with my account as well as on the Simulator so I think I have all requirements completed correctly but app still crashes. Error Domain=NSCocoaErrorDomain Code=134400 "Unable to initialize without a valid iCloud account (CKAccountStatusTemporarilyUnavailable)." UserInfo={NSLocalizedFailureReason=Unable to initialize without a valid iCloud account (CKAccountStatusTemporarilyUnavailable).} Not sure why my account status in temporarily unavailable. Any help would be much appreciated.
Posted
by
Post not yet marked as solved
0 Replies
412 Views
I recently started to learn CoreData with CloudKit in SwiftUI. It seems to be still quite a young solution (I know CoreData itself has been around for over a decade), so apart from some limited resources within the official documentation and archive, I get most information from the web. One thing that I had trouble with was storing in CoreData moderately complex data received in JSON format. Although I read that CoreData itself is not a relational database, it does look much alike to me, so my first choice would be to use relationships, but I saw people store arrays of data using attributes instead, e.g., in this StackOverflow thread. In my case, it would be an array of custom datatype objects, and while some resources on the web were helpful to get me quite far (e.g. this), I couldn't pull it off in the end. My question after this long background story is — in what situations would I choose attributes for storing collections of data instead of relationships? As an example, I currently have an entity Food in a to-many relationship with an entity Portion (a cup of rice, 8 oz of rice, etc.)
Posted
by