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

Posted

技术标签:

【中文标题】核心数据迁移:无法将“NSManagedObject_MyType”类型的值转换为“MyModule.MyType”【英文标题】:Core Data Migration: Could not cast value of type 'NSManagedObject_MyType' to 'MyModule.MyType' 【发布时间】:2017-09-12 10:52:49 【问题描述】:

我正在进行“中等重量”的核心数据迁移。我正在使用映射模型从一个旧存储/数据模型迁移到不同的存储和不同的模型(即完全不同的 .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
  

会抛出异常,错误信息为:

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

问题是,为什么会发生这种情况,这有关系吗?因为正在发生迁移,所以返回 NSManagedObject 以及正确的实体描述可能就足够了?

【问题讨论】:

我会直接跳到这里报告我的发现,这样其他人就不必花时间了。值得注意的摘录自“迁移过程”(您可以通过谷歌搜索并将您带到 Apple 网站...我不发布链接,因为 Apple 链接经常失效:)“迁移过程本身分为三个阶段。它使用禁用验证规则并且所有实体的类都更改为 NSManagedObject 的源模型和目标模型的副本。”所以是的,在这些策略中,您应该返回 NSManagedObject 而不是您的子类。 【参考方案1】:

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

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

您可以阅读更多关于我在 Core Data Migrations here 方面不太有趣的经历。

【讨论】:

以上是关于核心数据迁移:无法将“NSManagedObject_MyType”类型的值转换为“MyModule.MyType”的主要内容,如果未能解决你的问题,请参考以下文章

核心数据迁移问题:无法启动storePath

以前的核心数据迁移失败

将核心数据迁移到一个干净的开始

核心数据迁移要求

如何进行核心数据迁移?

通过迁移将核心数据实体及其数据移动到新的核心数据模型文件中