1

I am converting existing app from NSPersistentContainer to NSPersistentCloudKitContainer AppDelegate code:

 lazy var persistentContainer: NSPersistentCloudKitContainer = {
   
    let container = NSPersistentCloudKitContainer(name:"GridModel")

    // enable history tracking and remote notifications
     guard let publicStoreDescription = container.persistentStoreDescriptions.first else {
        fatalError("###\(#function): failed to retrieve a persistent store description.")
    }
    // public
    let publicStoreUrl = publicStoreDescription.url!.deletingLastPathComponent().appendingPathComponent("GridModel-public.sqlite")
    publicStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
    publicStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
    
    let containerIdentifier = publicStoreDescription.cloudKitContainerOptions!.containerIdentifier
    let publicStoreOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: containerIdentifier)
    if #available(iOS 14.0, *) {
        publicStoreOptions.databaseScope = CKDatabaseScope.public
    } else {
        // Fallback on earlier versions???
    }
    publicStoreDescription.cloudKitContainerOptions = publicStoreOptions
    print(containerIdentifier)
    
    container.loadPersistentStores(completionHandler: { (loadedStoreDescription, error) in
        if let loadError = error as NSError? {
            fatalError("###\(#function): Failed to load persistent stores:\(loadError)")
        } else if let cloudKitContainerOptions = loadedStoreDescription.cloudKitContainerOptions {
            if #available(iOS 14.0, *) {
                if .public == loadedStoreDescription.cloudKitContainerOptions?.databaseScope {
                    self._publicPersistentStore = container.persistentStoreCoordinator.persistentStore(for: loadedStoreDescription.url!)
                } else if .private == loadedStoreDescription.cloudKitContainerOptions?.databaseScope {
                    self._privatePersistentStore = container.persistentStoreCoordinator.persistentStore(for: loadedStoreDescription.url!)
                } else if .shared == cloudKitContainerOptions.databaseScope {
                    self._sharedPersistentStore = container.persistentStoreCoordinator.persistentStore(for: loadedStoreDescription.url!)
                }
            } else {
                // Fallback on earlier versions
            }
        } /*else if appDelegate.testingEnabled {
            if loadedStoreDescription.url!.lastPathComponent.hasSuffix("private.sqlite") {
                self._privatePersistentStore = container.persistentStoreCoordinator.persistentStore(for: loadedStoreDescription.url!)
            } else if loadedStoreDescription.url!.lastPathComponent.hasSuffix("shared.sqlite") {
                self._sharedPersistentStore = container.persistentStoreCoordinator.persistentStore(for: loadedStoreDescription.url!)
            }
        }*/
    })
    
    container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    container.viewContext.transactionAuthor = appTransactionAuthorName
    
   
    
    // Pin the viewContext to the current generation token, and set it to keep itself up to date with local changes.
    container.viewContext.automaticallyMergesChangesFromParent = true
    do {
        try container.viewContext.setQueryGenerationFrom(.current)
    } catch {
        fatalError("###\(#function): Failed to pin viewContext to the current generation:\(error)")
    }
    
    #if DEBUG
    do {
        // Use the container to initialize the development schema.
        try container.initializeCloudKitSchema(options: [])
    } catch {
        // Handle any errors.
        fatalError("###\(#function): failed to load persistent stores: \(error)")
    }
    #endif
    
    // Observe Core Data remote change notifications.
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(storeRemoteChange(_:)),
                                           name: .NSPersistentStoreRemoteChange,
                                           object: container.persistentStoreCoordinator)
    
    
    return container
    
}()

The very first time I run, Creates all the corresponding CD CKRecords in CloudKit public database _defaultZone. All values are copied from Core Data to CloudKit. When the app is actively running I deleted a Core Data record and added a new record it did not delete it from Cloud Kit. Also when I add a new record in Core Data it did not export and add to Cloud Kit. When the app is actively running any changes I make are not exported and updated in Cloud Kit. What changes should I make to the code?

But when I run the app again then all the previous changes that I made when the app was active are updated. So looks like it does not perform live updates until the app is rerun again.

I get another error on the Debug Console "Custom zones are not allowed in public DB". I am not writing to custom DB. I wonder if this is preventing active updates?

oreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _requestAbortedNotInitialized:](1983): <NSCloudKitMirroringDelegate: 0x2824d16c0> - Never successfully initialized and cannot execute request '<NSCloudKitMirroringExportRequest: 0x280a84780> FDB61E8D-658F-4C77-8615-EF07BAB72BAD' due to error: <CKError 0x28119ba20: "Partial Failure" (2/1011); "Failed to modify some records"; uuid = 6C66A151-DB59-4A1B-B3BD-02CFB9A4139C; container ID = "iCloud.com.greenendpoint.nr2r"; partial errors: {

B-63B7-45D2-BFE0-599972FB6FD7:(com.apple.coredata.cloudkit.zone:defaultOwner) = <CKError 0x2810e44e0: "Server Rejected Request" (15/2027); server message = "Custom zones are not allowed in public DB"; op = 23AFDAC55F70DC8D; uuid = 6C66A151-DB59-4A1B-B3BD-02CFB9A4139C>

Please help!
vrao
  • 545
  • 2
  • 12
  • 33
  • Did you select in the CloudKit Dashboard the correct zone "com.apple.coredata.cloudkit.zone"? – Reinhard Männer Nov 05 '22 at 16:47
  • I edited my earlier post as I made code changes and now the Core data Objects and values are exported to Cloud Kit public database correctly. However any changes I make when the app is running are not exported to and updated in Cloud kit. But when I run the app again then all the previous changes that I made when the app was previously active are updated. So looks like it does not perform live updates until the app is rerun again. How to fix this and ensure live updates happen from Core data to Cloud Kit? What changes should I make to the above code. – vrao Nov 06 '22 at 15:47
  • Maybe [this post](https://stackoverflow.com/a/69724705/1987726) can help you? – Reinhard Männer Nov 06 '22 at 17:08
  • I checked the post. Actually as suggested in the post I had created indices recordName as Queryable, modifiedTimeStamp as both queryable and sortable. Also in the dashboard security roles, _icloud, I ensured it has all three create, read, write permissions. Also as suggested in the post, for my CoreData DB default configuration used with CloudKit. Still getting the same error" Custom zones are not allowed in public DB" error and still not updating CloudKit in real-time when app is active. I am using Xcode 13.3.1 and iOS deployment tarte 15.3. I am missing something critical – vrao Nov 06 '22 at 19:00
  • When I add or delete a new Core data record while app is active, there is no output on Debug Console which tells me that live updates to cloud Kit is turned off. May be there is way to turn it on and I am missing it in the code or settings? – vrao Nov 06 '22 at 19:25

1 Answers1

0

It worked. I had to delete my app on the test device and restart again. Looks like it recreated the data store and synced with Cloud Kit.

vrao
  • 545
  • 2
  • 12
  • 33