NSPersistentCloudKitContainer migration with custom NSEntityMigrationPolicy

Recently, I have made quite extensive changes to my schema and need to migrate my CoreData + CloudKit model to a new version. The changes require me to use a custom NSEntityMigrationPolicy because I have a rather complex mapping between some old entities and new entities.

  1. I have added a new model version. Deleted some entities, and added some entities.
  2. I have defined the NSEntityMigrationPolicy with createDestinationInstances(forSource:in:manager:) and createRelationships(forDestination:in:manager:).
  3. I have created a new Core Data Mapping Model. This was probably unnecessary.
  4. Within the Core Data Mapping Model, I have specified Custom Policy for all entities.
  5. In my container setup, I added two options, as below:
storeDescription.setOption(false as NSNumber, forKey: NSMigratePersistentStoresAutomaticallyOption)

storeDescription.setOption(false as NSNumber, forKey: NSInferMappingModelAutomaticallyOption)

I mostly followed a "Core Data Heavyweight Migration" guide. I'm unable to share the link, but it can be quite easily found on the web. (It's not for CloudKit specifically.)

When I run my app, I am getting the most basic of errors, which is:

The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store.

So I guess that migration wasn't even attempted, which makes sense because I set NSMigratePersistentStoresAutomaticallyOption to false.

I tried to go beyond what I could find on the web and attempted to manually initialize migration:

let sourceModel = container.persistentStoreCoordinator.managedObjectModel

guard let modelURL = Bundle.main.url(forResource: "MyModelName", withExtension: "xcdatamodeld") else {
    fatalError("Unable to locate model file.")
}

guard let destinationModel = NSManagedObjectModel(contentsOf: modelURL) else {
    fatalError("Unable to load destination model.")
}
        
let migrationManager = NSMigrationManager(sourceModel: sourceModel, destinationModel: destinationModel)

let mappingModel = NSMappingModel(from: [Bundle.main], forSourceModel: sourceModel, destinationModel: destinationModel)!

migrationManager.currentEntityMapping.entityMigrationPolicyClassName = "MyMigrationPolicyClassName"

I am then stuck at the migrateStore(from:type:mapping:to:type:) method. It seems to target only local storage, not CloudKit. Otherwise, what do I provide for URLs and types?

Any guidance for custom logic CoreData with CloudKit migration would be greatly appreciated.

Replies

Save some hair and use SwiftData

  • I might move to SwiftData when iOS 17 becomes more prevalent, but I'm stuck with CoreData for the time being. (How easy is migrating CloudKit with SwiftData, though?)

    Also, I don't have that much hair to save at this point. :')

Add a Comment