CloudKit and CoreData public database

"Core Data with CloudKit uses a specific record zone in the CloudKit private database, which is accessible only to the current user."


It's not possible to use CloudKit and CoreData with the CloudKit public database? Here is my scenario.


- I have an application with two core data stores.

- The first store should be synced with the public CloudKit database and NOT updated by the user.

- The second store should be synced with the private CloudKit database and updated by the user.


lazy var persistentContainer: NSPersistentCloudKitContainer = {

    let container = NSPersistentCloudKitContainer(name: "MyAppName")
    
    // Create a store description for the first store
    let firstStoreLocation = URL(fileURLWithPath: "/path/to/first.store")
    let firstStoreDescription = NSPersistentStoreDescription(url: firstStoreLocation)
    firstStoreDescription.configuration = "First"
    
    // Create a store descpription for the second store
    let secondtoreLocation = URL(fileURLWithPath: "/path/to/second.store")
    let secondStoreDescription = NSPersistentStoreDescription(url: secondtoreLocation)
    secondStoreDescription.configuration = "Second"

    // Set the container options on the first store
    firstStoreDescription.cloudKitContainerOptions = 
        NSPersistentCloudKitContainerOptions(containerIdentifier: "com.my.container1")

    // Set the container options on the second store
    secondStoreDescription.cloudKitContainerOptions = 
        NSPersistentCloudKitContainerOptions(containerIdentifier: "com.my.container2")
    
    // Update the container's list of store descriptions
    container.persistentStoreDescriptions = [
        firstStoreDescription,
        secondStoreDescription
    ]
    
    // Load both stores
    container.loadPersistentStores { storeDescription, error in
        guard error == nil else {
            fatalError("Could not load persistent stores. \(error!)")
        }
    }
    
    return container
    
}()


This code would setup sync with two stores and two different containers with private databases?

It would be great if you could use the same container but different databases.

Replies

I believe that yes, it will create two stores and two different containers with private databases. I used to think, incorrectly, that there was a 1 to 1 mapping between an instance of NSPersistentCloudKitContainer, and a single CloudKit store description, but I've come to realize that one instance can handle multiple cloud synced stores.


"When working with multiple stores, create an instance of

NSPersistentCloudKitContainerOptions
for each store you wish to use with CloudKit."


And no, you can't access the public, or shared database with Core Data for CloudKit.


Also, if you want to write to the public database but not as an individual user, you can't do that through the iOS CloudKit API. CloudKit CKRecord instances are always owned by the user who created them. You'd have to use a server to server key and use their REST API from your app. That way you can write records as admin. I was thinking of using the public database to store app configuration data, but I'm not sure I want to develop with yet another interface, although I'll probably have to because of subscription management.

More info: I have experimented with code similar to yours to initialize two CloudKit schemas with one single request on the single NSPersistentCloudKitContainer instance. It does indeed work, however,there are limitations with the Xcode schema designer which render the results, effectively useless. The problems start when you create multiple configurations in your schema model, that are declared to be used with CloudKit. The schema designer has no knowledge of container identifiers, nevermind multiple container identifiers. I discovered that as soon as I added a new CloudKit backed configuration and added a single new entity to it with zero relationships, my project no longer compiled. Xcode told me that I had to add the entities from the other CloudKit backed configuration to this new configuration with it's single isolated entity. Bizarrely, it never instructed me to add the new isolated entity to the previous CloudKit configuration. It was complaining about relationships in the older CloudKit configuration in relation to the new configuration.


It then complied successfully. Not so happy days though. Because the model wasn't actually correct, or what I wanted. After running the schema initialization, it created an accurate representation of the CloudKit schema configurations correctly, but the second one also contained CKRecord definitions for the entities Xcode told me to copy into my second CloudKit configuration. So both iCloud containers had a record definition for my Resource entity, which wasn't what I wanted.


I would stick to using a single schema design .datamodeld file for each iCloud container you want to sync against. You can't create cross-container relationships anyway, so you're actually not losing anything. You'd just have to decide upfront which entities should belong in which schema/iCloud container.


So the failed experiment created CKRecord definitions for a single entity (in my only schema model) in multiple iCloud containers. This might mean that you could use this scenario to write the same data to multiple iCloud containers, with no extra effort on your part. I might look into this and see if it actually works.