I'm in the middle of updating my app to only support iOS 14+ and am moving to the new @main app structure. I'm trying to figure out how to deal with code in my App and Scene Delegate: mainly code related to Core Data and CloudKit persistent container. Stuff like lazy var persistentContainer: NSPersistentCloudKitContainer = {...} and let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy context.automaticallyMergesChangesFromParent = true Where do I put this kind of stuff in the new @main world?
Search results for
NSPersistentCloudKitContainer
589 results found
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I believe that right now there's no way to be notified when the sync status of an NSPersistentCloudKitContainer changes. Is my assumption correct? I'd like to know if there are pending changes to be synced or when the sync starts/ends to be able to reflect it on the UI to inform my users. Any ideas on how (or if it's possible) to achieve what I need? Thank you!
I've seen that the documentation of NSPersistentCloudKitContainer has been updated after the WWDC with two new Type Properties: class let eventChangedNotification: NSNotification.Name and class let eventNotificationUserInfoKey: String I think that are related to your question but I haven't tried them. I'm looking for this feature from the last year and I hope that in iOS 14 it will be implemented.
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
My two cents... My Core Data implementation for SwiftUI using the new App and Scene protocols and Window container! Credit to: mtsrodrigues for how to deal with change of Scene in his answer in this thread. KrakenDev's article on how to write a one line singleton My SwiftUI App... import SwiftUI @main struct YourApp: App { @Environment(.scenePhase) private var scenePhase @StateObject private var persistentStore = PersistentStore.shared var body: some Scene { WindowGroup { ContentView() .environment(.managedObjectContext, persistentStore.context) } .onChange(of: scenePhase) { phase in switch phase { case .active: print((#function) REPORTS - App change of scenePhase to ACTIVE) case .inactive: print((#function) REPORTS - App change of scenePhase to INACTIVE) case .background: print((#function) REPORTS - App change of scenePhase to BACKGROUND) savePersistentStore() @unknown default: fatalError((#function) REPORTS - fatal error in switch statement for .onChange modifier) } } } func savePersistentStore() { persiste
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
So for any passers-by that are interested in how I eventually achieved this... (Credit to mtsrodrigues for how to deal with change of Scene in his answer in this thread... https://developer.apple.com/forums/thread/650876) My Core Data implementation for SwiftUI and the new App and Scene protocols and Window container! My SwiftUI App... struct MyApp: App { @Environment(.scenePhase) private var scenePhase @StateObject private var persistentStore = PersistentStore.shared var body: some Scene { WindowGroup { ContentView() .environment(.managedObjectContext, persistentStore.context) } .onChange(of: scenePhase) { phase in switch phase { case .active: print((#function) REPORTS - App change of scenePhase to ACTIVE) case .inactive: print((#function) REPORTS - App change of scenePhase to INACTIVE) case .background: print((#function) REPORTS - App change of scenePhase to BACKGROUND) savePersistentStore() @unknown default: fatalError((#function) REPORTS - fatal error in switch statement for .onChange modifier) } } } func
Topic:
UI Frameworks
SubTopic:
General
Tags:
After many months/years of trying to create my own CoreData/iCloud sync engine, and getting about 90% of the way there; I gave up and started using NSPersistentCloudKitContainer, forcing us to drop support for iOS 12-. At first all seemed fine, however, today it all went horribly wrong (still investigating why) I now have 'duplicate' CKRecords of single ManagedObjects in CloudKit, and (it seems, although still tracking down the model) disconnected 'references'. Having looked at CloudKit Dashboard is seems that NSPersistentCloudKitContainer does not use ANY references, but simply a String of the UUID of the referenced CKRecord. I can only presume that this is a workaround to prevent Referencing a (not yet) non-existent CKRecord. So, this presents several questions: Is the lack of CKReference by design, or a bug? What defensive programming is in place to prevent duplications or corrupt references when using Stringly-Typed pseudo-references? Is there a way to inform the NSPersistentCloudKitContainer
I was able to fix this by moving my data store into its own class and using the same thing for both the app and previews: import CloudKit import CoreData import Foundation class DataStore { static let shared = DataStore() lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentCloudKitContainer(name: Structure) container.loadPersistentStores(completionHandler: { _, error in if let error = error { fatalError(Unresolved error (error)) } let context = container.viewContext context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy context.automaticallyMergesChangesFromParent = true // other setup here }) return container }() func saveContext() { let context = persistentContainer.viewContext if context.hasChanges { do { try context.save() } catch { fatalError(Unresolved error (error)) } } } }
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
I've found the solution. On the NSPersistentCloudKitContainer we have to simply call persistentContainer.record(for: object.objectID) where object is NSManagedObject
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
No, unfortunately if you hadn't set true for key NSPersistentHistoryTrackingKey, they will never get it to cloud, they will stay only in your device. A workaround that I used and worked fine, is to add a property to all entities (I used cloudReady: Bool, and at the first run of the app, after you adopt NSPersistentCloudKitContainer, change that property to true for all entities. This will force iCloud to sync those objects.
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
In session wwdc20-10650 - https://developer.apple.com/videos/play/wwdc2020/10650/ Sync a Core Data store with the CloudKit public database at 14:22, Nick says NSPersistentCloudKitContainer can't use CKFetchRecordZoneChangesOperation with the public database, it has to use CKQueryOperation. I was wondering why didn't you use CKSubscription? Create a subscription for each record type and the CKQueryNotification can contain CKQueryNotificationReasonRecordDeleted. It's been a while since I worked on my own public database sync but I think that is how I did it. This is the second time I've heard of the sync design being affected by limitations of CloudKit and it worries me. The first time it was when you decided not to use CKReference and instead create your own relation records because you said CloudKit had a limit on the number of references. Personally I didn't think the number was too low and I didn't understand why it couldn't just be raised, and if you had paired that with the non-public CKReference
I'm really excited about the new public database options introduced in the Sync a Core Data store with the CloudKit public database talk! I see in the documentation that the databaseScope refers to the CKDatabase.Scope which includes an option for the shared database. Does this mean that we will be able to automatically sync CoreData records to a shared CloudKit database this year? I would really like to add support to my app to sync data with friends through CloudKit, but with the existing system it is too much work to sync shared objects through a CKShare, so I have avoided building it so far. I'm really excited to start using the new changes. Thanks!
This thread provides an example of a SwiftUI + Core Data setup: https://developer.apple.com/forums/thread/650876 To clarify some terms: Core Data is a framework for local persistence and CloudKit can be seen as a transport technology that deals with storing data in iCloud. If you want to store objects from Core Data in iCloud, you can implement the syncing behavior on your own or make use of NSPersistentCloudKitContainer, a class that automatically mirrors changes in a local Core Data container to iCloud and keeps each device up-to-date.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
@micho2, to achieve CloudKit integration you should be able to change the persistentContainer property like so... var persistentContainer: NSPersistentContainer = { ttttlet container = NSPersistentCloudKitContainer(name: SampleApp) tttttt // change this line container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { ttttttttfatalError(Unresolved error (error), (error.userInfo)) } }) ttttcontainer.viewContext.automaticallyMergesChangesFromParent = truetttttttt // add this line return container }() although I've not tested this yet!
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
CKDatabase.Scope is also used in other classes, such as CKDatabase. Introducing a new scope class just for NSPersistentCloudKitContainer wouldn't have been a good idea.
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
NSPersistentCloudKitContainer only supports the private database and the public database. If you want to let your users share data with each other, you need to use the CKShare and CK operations API.
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags: