Value of type 'NSPersistentCloudKitContainerOptions' has no member 'shouldInitializeSchema'

I'm trying to re-initialize a CloudKit container using the instructions in the docs. This worked in XCode 11 beta 3 or 4 (when I first initialized it), possibly running on Mac OS 10.14.x. I'm now running on Mac OS 10.15 beta 4 (19A512f), running Xcode 11 beta 4, and get "Value of type 'NSPersistentCloudKitContainerOptions' has no member 'shouldInitializeSchema'" for the indicated line below (line 4):


        // Initialize the CloudKit schema. This should be toggled off or removed when shipping the app.
        let containerId = "iCloud.com."
        let options = NSPersistentCloudKitContainerOptions(containerIdentifier: containerId)
-->     options.shouldInitializeSchema = true // toggle to false when done, or true to initialize iCloud schema
        description.cloudKitContainerOptions = options


I've tried running clean build, running xcode-select -s /Applications/Xcode-beta.app, and building to a different iOS device and consistently get this error. The most up-to-date documentation I can find for NSPersistentCloudKitContainerOptions shows that shouldInitializeSchema is a Boolean variable.


Thought I'd post here before submitting a bug in Feedback.


Thanks!

Accepted Reply

Thanks. I found documentation in Xcode Core Data framework files

    /*
     This method creates a set of representative CKRecord instances for all stores in the container
     that use Core Data with CloudKit and uploads them to CloudKit. These records are "fully saturated"
     in that they have a representative value set for every field Core Data might serialize for the given
     managed object model.
     
     After records are successfully uploaded the schema will be visible in the CloudKit dashboard and
     the representative records will be deleted.
     
     This method returns YES if these operations succeed, or NO and the underlying error if they fail.
     
     Note: This method also validates the managed object model in use for a store, so a validation error
     may be returned if the model is not valid for use with CloudKit.
     */
    open func initializeCloudKitSchema(options: NSPersistentCloudKitContainerSchemaInitializationOptions = []) throws

Replies

Same issue.

MacOS 10.14.5

Xcode 11.0 beta 4


        let options = NSPersistentCloudKitContainerOptions(containerIdentifier: id)
        options.shouldInitializeSchema = true // error


I got an error:

Value of type 'NSPersistentCloudKitContainerOptions' has no member 'shouldInitializeSchema'


NSPersistentCloudKitContainerOptions class declaration

@available(iOS 13.0, *)
open class NSPersistentCloudKitContainerOptions : NSObject {

    /**
     The container identifier of the CKContainer to use with a given instance of NSPersistentStoreDescription
     */
    open var containerIdentifier: String { get }

    
    public init(containerIdentifier: String)
}

This doesn't seem to be documented anywhere, but it looks like in iOS 13 beta 4 there's a new `NSPersistentCloudKitContainer.initializeCloudKitSchemaWithOptions` method. Take a look at the API diffs here: http://codeworkshop.net/objc-diff/sdkdiffs/ios/13.0b4/CoreData.html

Thanks. I found documentation in Xcode Core Data framework files

    /*
     This method creates a set of representative CKRecord instances for all stores in the container
     that use Core Data with CloudKit and uploads them to CloudKit. These records are "fully saturated"
     in that they have a representative value set for every field Core Data might serialize for the given
     managed object model.
     
     After records are successfully uploaded the schema will be visible in the CloudKit dashboard and
     the representative records will be deleted.
     
     This method returns YES if these operations succeed, or NO and the underlying error if they fail.
     
     Note: This method also validates the managed object model in use for a store, so a validation error
     may be returned if the model is not valid for use with CloudKit.
     */
    open func initializeCloudKitSchema(options: NSPersistentCloudKitContainerSchemaInitializationOptions = []) throws

For anyone else finding this:


  1. You need to call container.initializeCloudKitSchema() after container.loadPersistentStores.
  2. You don't really need to call container.initializeCloudKitSchema() at all, as CloudKit will create your schema on the fly. initializeCloudKitSchema just sends some fake data for your model, so it's handy to see if anything's going to break that Xcode didn't warn you about.


Here's some code that works in Xcode 11 beta 5 to initialize an NSPersistentCloudKitContainer using a local store and a cloud store (see the Manage Multiple Stores section of the Setting Up Core Data doc).


    // MARK: - Core Data stack

    /// Convenience method so you can do DataManager.shared.context instead of DataManager.shared.persistentContainer.viewContext.
    lazy var context = self.persistentContainer.viewContext

    /// persistentContainer.viewContext
    lazy var persistentContainer: NSPersistentContainer = {
        /*
         The persistent container for the application. This implementation
         creates and returns a container, having loaded the store for the
         application to it. This property is optional since there are legitimate
         error conditions that could cause the creation of the store to fail.
         */
        let container = NSPersistentCloudKitContainer(name: "Model")

        // Put our stores into Application Support
        var storePath: URL
        do {
            storePath = try FileManager.default.url(for: .applicationSupportDirectory,
                                                    in: .userDomainMask,
                                                    appropriateFor: nil,
                                                    create: true)
        } catch {
            fatalError("Unable to get path to Application Support directory")
        }

        // Create a store description for a local store
        let localStoreLocation = storePath.appendingPathComponent("local.store")
        let localStoreDescription =
            NSPersistentStoreDescription(url: localStoreLocation)
        localStoreDescription.configuration = "Local"

        // Create a store descpription for a CloudKit-backed local store
        let cloudStoreLocation = storePath.appendingPathComponent("cloud.store")
        let cloudStoreDescription =
            NSPersistentStoreDescription(url: cloudStoreLocation)
        cloudStoreDescription.configuration = "Cloud"


        // Set the container options on the cloud store
        cloudStoreDescription.cloudKitContainerOptions =
            NSPersistentCloudKitContainerOptions(
                containerIdentifier: "iCloud.com.mydomain.mycontainer")

        // Update the container's list of store descriptions
        container.persistentStoreDescriptions = [
            cloudStoreDescription,
            localStoreDescription
        ]

        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate.
                // You should not use this function in a shipping application, although it may be useful during
                // development.
                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device
                 *     is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo) for \(storeDescription)")
            }
        })

        do {
              // Uncomment to do a dry run and print the CK records it'll make
//            try container.initializeCloudKitSchema(options: [.dryRun, .printSchema])
            // Uncomment to initialize your schema
            try container.initializeCloudKitSchema()
        } catch {
            print("Unable to initialize CloudKit schema: \(error.localizedDescription)")
        }

        return container
    }()

You don't really need to call container.initializeCloudKitSchema() at all, as CloudKit will create your schema on the fly. initializeCloudKitSchema just sends some fake data for your model, so it's handy to see if anything's going to break that Xcode didn't warn you about.


This is wrong. Please refer to the WWDC talk this year.


NSPersistentCloudKitContainer
materializes a number of specific values in your record that may not be initialized properly simply by using your app. Specifically for variable length fields like data blobs and strings you are unlikely to trivially violate our asset threshold during normal use.

Thank you for addressing this, I was going to query it because it went against everything I'd read. Do you know if it's possible to capture the output of the schema initialization process when using the option .printSchema? I'd quite like to save it to a file and also search for the success text so my integration test can respond accordingly. Do you think it would work if I ran it in a seperate Process and just redirected stdout? Wait that won't work because Process is a macOS only class and even so, you can't set iCloud Container entitlements on a command line application. Which I wish you could...

It's been 5 months, we are well out of beta, and I think the doucmentation is still wrong, telling you to set options.shouldInitializeSchema

This helped a lot.
I missed just this line, because I had wrapped the options in a var and forgot to finally apply the option to the "cloudStoreDescription".


cloudStoreDescription.cloudKitContainerOptions =  
            NSPersistentCloudKitContainerOptions(  
                containerIdentifier: "iCloud.com.mydomain.mycontainer")