Недавно я внес довольно значительные изменения в свою схему, и мне нужно перенести модель CoreData + CloudKit в новую версию. Изменения требуют от меня использования пользовательского NSEntityMigrationPolicy
, потому что у меня довольно сложное сопоставление между некоторыми старыми и новыми объектами.
NSEntityMigrationPolicy
с помощью createDestinationInstances(forSource:in:manager:)
и createRelationships(forDestination:in:manager:)
.storeDescription.setOption(false as NSNumber, forKey: NSMigratePersistentStoresAutomaticallyOption)
storeDescription.setOption(false as NSNumber, forKey: NSInferMappingModelAutomaticallyOption)
В основном я следовал руководству Core Data Heavyweight Migration. (Это не специально для CloudKit.)
Когда я запускаю свое приложение, я получаю самые основные ошибки:
Версия модели управляемых объектов, использованная для открытия постоянного хранилища, несовместима с той, которая использовалась для создания постоянного хранилища.
Итак, я предполагаю, что попытка миграции даже не предпринималась, что имеет смысл, поскольку я установил для NSMigratePersistentStoresAutomaticallyOption
значение false.
Я попытался выйти за рамки того, что смог найти в Интернете, и попытался вручную инициализировать миграцию:
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"
Тогда я застрял на методе migrateStore(from:type:mapping:to:type:)
. Кажется, он нацелен только на локальное хранилище, а не на CloudKit. В противном случае, что мне предоставить для URL-адресов и типов?
Мой вопрос: как реализовать собственную логику для CoreData с помощью миграции CloudKit?
Мне удалось решить эту проблему, адаптировав прогрессивную модель миграции основных данных , как объяснил Уильям Боулс .
Эта реализация работает с NSPersistentCloudKitContainer
. Насколько я знаю, вам не нужно устанавливать storeDescription.type
для контейнера, потому что NSPersistentCloudKitContainer
управляет хранилищами под капотом.
После загрузки магазинов вам нужно будет инициализировать схему, например:
do {
try self.container.initializeCloudKitSchema(options: [])
} catch let error {
fatalError("###\(#function) failed to initialize CloudKit schema due to error: \(error.localizedDescription)")
}
Этот код не будет работать, если ваше устройство/симулятор разработки не зарегистрировано в iCloud.
Затем вам также потребуется открыть консоль CloudKit и развернуть вашу схему в рабочей среде.