核心数据迁移:无法将types“NSManagedObject_MyType”的值转换为“MyModule.MyType”

我正在做一个“中等重量”的核心数据迁移。 我正在使用映射模型从一个传统存储/数据模型迁移到不同的存储和不同的模型(即完全不同的.xcdatamodeld )文件,并在适用的情况下使用自定义的NSEntityMigrationPolicy对象。

以前我有各种与对象图无关的对象,现在我想拥有一个主对象Library ,使我能够轻松地清除所有关联的数据(使用级联删除规则)。

由于NSEntityMigrationPolicy子类中的自定义方法,我在迁移过程中遇到了问题:

 class LegacyToModernPolicy: NSEntityMigrationPolicy { func libraryForManager(_ manager: NSMigrationManager) -> Library { let fetchRequest: NSFetchRequest<Library> = NSFetchRequest(entityName: Library.entity().name!) fetchRequest.predicate = nil fetchRequest.sortDescriptors = [NSSortDescriptor(key: "filename", ascending: true)] fetchRequest.fetchLimit = 1 do { // will fail here if NSFetchRequest<Library> let results = try manager.destinationContext.fetch(fetchRequest) log.info("results: \(results)") if results.count == 1 { // can fail here if NSFetchRequest<NSManagedObject> return results.first! as! Library } else { let newLib = Library(context: manager.destinationContext) return newLib } } catch { log.error("Error fetching: \(error.localizedDescription)") } let newLib = Library(context: manager.destinationContext) return newLib } } 

将抛出exception,并且错误消息是:

Could not cast value of type 'NSManagedObject_Library_' (0x6100000504d0) to 'SongbookSimple.Library' (0x101679180).

问题是,这是为什么发生,这是否重要? 因为迁移正在发生,也许这足以返回正确的实体描述NSManagedObject

原因是在迁移期间,你不应该使用NSManagedObject子类的实例。 你需要以NSManagedObject的formsexpression所有这些。 所以上面的代码必须变成:

 class LegacyToModernPolicy: NSEntityMigrationPolicy { static func find(entityName: String, in context: NSManagedObjectContext, sortDescriptors: [NSSortDescriptor], with predicate: NSPredicate? = nil, limit: Int? = nil) throws -> [NSManagedObject] { let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest(entityName: entityName) fetchRequest.predicate = predicate fetchRequest.sortDescriptors = sortDescriptors if let limit = limit { fetchRequest.fetchLimit = limit } do { let results = try context.fetch(fetchRequest) return results } catch { log.error("Error fetching: \(error.localizedDescription)") throw error } } func libraryForManager(_ manager: NSMigrationManager) -> NSManagedObject { do { var library: NSManagedObject? = try LegacyToModernPolicy.find(entityName: Library.entity().name!, in: manager.destinationContext, sortDescriptors: [NSSortDescriptor(key: "filename", ascending: true)], with: nil, limit: 1).first if library == nil { let dInstance = NSEntityDescription.insertNewObject(forEntityName: Library.entity().name!, into: manager.destinationContext) // awakeFromInsert is not called, so I have to do the things I did there, here: dInstance.setValue(Library.libraryFilename, forKey: #keyPath(Library.filename)) dInstance.setValue(NSDate(timeIntervalSince1970: 0), forKey: #keyPath(Library.updatedAt)) library = dInstance } return library! } catch { fatalError("Not sure why this is failing!") } }} 

你可以在这里阅读更多关于我对核心数据迁移的不那么有趣的经验。