NSPersistentCloudKitContainer with public database doesn't work and is poorly documented

So I tried the public database feature of NSPersistentCloudKitContainer last year but never really got anywhere so I thought i'd try it again this year.

However I've still had basically no luck and I figured now might be a good time to try and document the issues I have had.

  1. The documentation for this at https://developer.apple.com/documentation/coredata/mirroring_a_core_data_store_with_cloudkit/creating_a_core_data_model_for_cloudkit mentions shouldInitializeSchema which from what I can gather was removed in a beta version a long ** time ago. It appears to now be a method on the container - container.initializeCloudKitSchema(). Ya'll should update this documentation.

  2. initializeCloudKitSchema does not work if you have options.databaseScope = .public on the NSPersistentCloudKitContainerOptions. You get a bunch of errors saying "No authToken received for asset"

  3. Turning off the public scope and then calling initializeCloudKitSchema gets you the Record types you need created in the CloudKit console, then removing the initialise code and setting it back to public, it APPEARS to work, but then...

  4. The WWDC video from 2020 says that before you can sync you need to add two indexes to each record type recordName and modifiedAt however if you get this far you will have no such fields. After running it a few times and scouring through the logs you will spot a few errors telling you about missing indexes - adding querable index to recordID, and queryable + searchable to modTime gets you something that.... appears to work... kind of.

  5. Ok so you get this far, and you insert some object into your store and save them - and they appear on the cloudkit server, huzzah!. Then you delete the app and reinstall it, and the objects appear in your app, huzzah! However you will now start getting a ton of these kinds of errors in your log:

com.apple.coredata.cloudkit.zone:__defaultOwner__ = <CKError 0x2814192f0: "Server Rejected Request" (15/2027); server message = "Custom zones are not allowed in public DB"; op = 8F0FD95A1EFB2348; uuid = F1DCD158-BA28-4E20-AD18-723F603A0C00>

And if you use your app to add or edit any objects they won't make it to CloudKit any more. However, adding new objects via the console will make them appear in the app.

At this point I kinda gave up.

Can somebody tell me I am an *****, or does this feature legitimately not work?

initializeCloudKitSchema does not work if you have  options.databaseScope = .public on the NSPersistentCloudKitContainerOptions. You get a bunch of errors saying "No authToken received for asset"

You can file a feedback report for this and use a private scoped database to initialize your container as a workaround.

The WWDC video from 2020 says that before you can sync you need to add two indexes to each record type recordName and modifiedAt however if you get this far you will have no such fields. After running it a few times and scouring through the logs you will spot a few errors telling you about missing indexes - adding querable index to recordID, and queryable + searchable to modTime gets you something that.... appears to work... kind of.

recordName and modifiedAt are default fields on every record type, so if they are missing you should definitely file a feedback report with CloudKit.

com.apple.coredata.cloudkit.zone:defaultOwner = <CKError 0x2814192f0: "Server Rejected Request" (15/2027); server message = "Custom zones are not allowed in public DB"; op = 8F0FD95A1EFB2348; uuid = F1DCD158-BA28-4E20-AD18-723F603A0C00>

This looks like you tried to use a database file with the public database that was previously syncing with the private database. If you can reproduce this from a clean (empty) database file and some set of steps we'd appreciate a feedback report with a test case in it we can run

I've had a similar problem trying to get the "boiler plate" app code that is generated by Xcode for a new project to run correctly. The App (which worked in Xcode12.x) not tries to connect to iCloud and appears to have authentication problems... it generates "failed to sync users" messages when it tried to connect on a simulator that has a valid user signed in.

Steps to repeat:

  1. Start a new project in Xcode 12.x with CloudKit and CoreData enabled

  2. Enable the remote notifications and iCloud capabilities, selecting CloudKit and creating a new container

  3. Make a couple of changes to the ContentView to fix the error in the generated code (needs to include a PaginationView and wrap the toolbar elements in ToolbarItem Views)

  4. Run on two signed-in simulators and observe the synchronisation working (noting that perhaps now you need to close the app and restart it for the sync to work, instead of the old minimise refresh trick)

  5. Close Xcode 12.x and start the Xcode 13 Beta

  6. Load and build the previous project on two simulators

  7. Note now that the app no longer appears to talk to iCloud properly`

I'd be wrapped if someone could tell me I've stuffed up, but it feels like a problem with the Beta environment.

Andy

Hey thanks for replying!

You can file a feedback report for this and use a private scoped database to initialize your container as a workaround.

Done! FB9179243

recordName and modifiedAt are default fields on every record type, so if they are missing you should definitely file a feedback report with CloudKit.

I have a feeling this might just be a display issue in the CloudKit dashboard UI - Maybe new with the new dashboard update? I've never really used CloudKit 'in anger' so I don't really know.

What appears as 'Name' in both the "Records" table and "Record Details" sidebar, seems to be "recordID" if filtering, and also in the field dropdown when you are creating the index. So I guess it is there, it's just not named what I was expecting.

And it's the same situation for modified.

Does this sound right?

This looks like you tried to use a database file with the public database that was previously syncing with the private database. If you can reproduce this from a clean (empty) database file and some set of steps we'd appreciate a feedback report with a test case in it we can run

I am definitely using a coredata database file that has never touched the private database. It's reproduce-able. I've tried with a few different CoreData schemas to see if it was something I was doing there but that appears to have no effect.

The TLDR is:

  • If the core data store is empty, creating records will send them up to CloudKit
  • If the store is NOT empty, and the database syncs (e.g. app launch), you will get the "Custom zones are not allowed in public DB" errors
  • Once you are in this state with the ""Custom zones are not allowed in public DB" errors, changes from the device will no longer make it to iCloud
  • However, if you make a record off-device (e.g. In the Dashboard, via the API, or from another device), it will make it down to the device.

I created a feedback: FB9179204

I created a feedback: FB9179204

Thanks. But you didn't attach your application's persistent store from the reproduction. We'll need that to investigate further.

I have the same problem wth the public database but mine is compounded with needing to be pre-seeded with a few thousand records. Some devices happily update when you add new records, some do not This may be an ios 15 beta issue). All are using the same apple id. I also found that the CDMR type was never added to the dashboard despite there being logical connections between entities in coredata, so I had to create that by hand. Deleting records from the public database through the dashboard never seem to be reflected on the local database.

I'm now only getting the error on a device with iOS15 beta installed. And that device also seems to fail to sync with new server data. IOS14 devices have no errors and receive new records added by a different device. Syncing with private databases works fine on ios15 but public throws the error described above and never seems to receive updates.

Thanks for the detailed description of the problem, I'm having exactly the same issues and I'm really glad to finally found this post as my googling it earlier didn't point to anything. I just started trying public CloudKit database with iOS 15 and Xcode 13, so the last issue about custom zone com.apple.coredata.cloudkit.zone is most likely a newly introduced problem with iOS 15 where core data up sync always tries to add records in this zone (like it does with private database), while the CloudKit side doesn't allow it.

Same issue for me, if I set up a second device to work with a public database only, I get

UserInfo={NSLocalizedFailureReason=Request 'A72DA6B1-AFA0-4BC1-A116-518B36E9709C' was aborted because the mirroring delegate never successfully initialized due to error: <CKError 0x155c4230: "Partial Failure" (2/1011); "Failed to modify some record zones"; uuid = FDFC2AB5-2552-4A27-AF85-980AF61942CA; container ID = "XXXXXXX"; partial errors: { com.apple.coredata.cloudkit.zone:defaultOwner = <CKError 0x157e8360: "Server Rejected Request" (15/2027); server message = "Custom zones are not allowed in public DB"; op = D361CF9F4B166EE8; uuid = FDFC2AB5-2552-4A27-AF85-980AF61942CA>

..on the first device were the project was developed with, everything works just fine. I am only writing on the _defaultZone, meaning I did not set up a custom Zone as stated by the error messsage.

any idea? Thank you!

I was also getting the "Custom zones are not allowed. in the public DB" message when no custom zone had been created on every run of the app I was developing except for the the first run, so it sounds broadly similar to your issue. Xcode 13.1 was installed this morning, and it was still an issue, but when I also upgraded my test device to iOS 15.1 the issue now appears to have cleared and I can sync to the public database again. Don't know if it was iOS 15.1 or the combination of the two.

NSPersistentCloudKitContainer with public database doesn't work and is poorly documented
 
 
Q