2

In the following link, there is the source code for a project that allows you to sync core data between the same user devices. Data is stored in User Private Database... is there a way to sync data from CoreData in public CloudKit database so the app will be the same between ALL app users? Why NSPersistentCloudKitContainer doesn't allow you to set this?

https://developer.apple.com/documentation/coredata/synchronizing_a_local_store_to_the_cloud

1
  • I haven't read the docs but I imagine it could be a load problem if many users were making changes to a shared db, the sync problem would be enormous. Commented Mar 20, 2020 at 16:10

2 Answers 2

8

This is now possible in iOS 14.0+ Beta and macOS 11.0+ Beta via the new databaseScope property: https://developer.apple.com/documentation/coredata/nspersistentcloudkitcontaineroptions/3580372-databasescope

The possible values are .public (the public database), .private (the private database) and .shared (the shared database).

E.g.:

let container = NSPersistentCloudKitContainer(name: "test")
guard let description = container.persistentStoreDescriptions.first else {
    fatalError("Error")
}
description.cloudKitContainerOptions?.databaseScope = .public

The video https://developer.apple.com/videos/play/wwdc2020/10650 describes how to sync the Core Data store with the CloudKit public database by setting the databaseScope value to .public.

You may also need an #available check to ensure backwards compatibility, ie:

if #available(iOS 14.0, *) {
    description.cloudKitContainerOptions?.databaseScope = .public
} else {
    // Fallback on earlier versions
}
Sign up to request clarification or add additional context in comments.

4 Comments

Yep. Seems like in addition we have to manually create indices in CloudKit dashboard for the custom entities.
Adding to @JonEasy's comment: in Cloudkit Dashboard, mark the recordName and modifiedAt indices as "queryable"
is it possible to set databaseScope for each record? Ex: record 1 is on private, public and shared record 2 is on private and public etc...
@Mane Manero did you get an answer on this question ? (.public and . private on the same store)
3

To answer last question in comments, yes it is possible use .public and . private on the same store. This is the link to the project: Messanger by Patrick Maltagliati on 10/2/20

   init(inMemory: Bool = false) {
    container = NSPersistentCloudKitContainer(name: "Messanger")
    
    let defaultDesctiption = container.persistentStoreDescriptions.first
    let url = defaultDesctiption?.url?.deletingLastPathComponent()
    
    let privateDescription = NSPersistentStoreDescription(url: url!.appendingPathComponent("private.sqlite"))
    let privateOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.com.Maltagliati.Messanger")
    privateOptions.databaseScope = .private
    privateDescription.cloudKitContainerOptions = privateOptions
    privateDescription.configuration = "Private"
    privateDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
    privateDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
    
    let publicDescription = NSPersistentStoreDescription(url: url!.appendingPathComponent("public.sqlite"))
    let publicOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.com.Maltagliati.Messanger")
    publicOptions.databaseScope = .public
    publicDescription.cloudKitContainerOptions = publicOptions
    publicDescription.configuration = "Public"
    publicDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
    publicDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
    
    container.persistentStoreDescriptions = [privateDescription, publicDescription]
    
    if inMemory {
        container.persistentStoreDescriptions.forEach { $0.url = URL(fileURLWithPath: "/dev/null") }
    }
    
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.