Lorenzo Fiamingo
Lorenzo Fiamingo

Reputation: 4069

Synchronizing Core Data to CloudKit Public Database

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

Upvotes: 2

Views: 2532

Answers (2)

RichStwrt
RichStwrt

Reputation: 95

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)")
        }
    })
}

Upvotes: 3

Bas
Bas

Reputation: 186

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
}

Upvotes: 8

Related Questions