【问题标题】:Downcasting NSManagedObject in Swift Core Data在 Swift Core Data 中向下转换 NSManagedObject
【发布时间】:2016-02-11 02:24:32
【问题描述】:

我有一个继承自 NSManagedObject 的类。我将这个对象用于模型数据并且它也被持久化了。

class Foo: NSManagedObject {

   @NSManaged var firstVar: String
   @NSManaged var secondVar: String

  let entity = NSEntityDescription.entityForName("Foo",   inManagedObjectContext: managedObjectContext)
  let createdManagedObject = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedObjectContext) as? Foo

}

我可以创建对象并获取NSManagedObject 实例,但我不能将其转换为实际类。 实际上,如果我将其向下转换为可选值,那么我将得到 nil 值,如果我通过展开向下转换,那么它将崩溃。 当使用 nil 值进行向下转换时,调试器检查器显示类型:Module.Foo,我认为这是问题的根源。

当然,我尝试在 .xcmod​​el 检查器中命名类,尝试将 Entity 命名为 Module.Foo,但从 Xcode 7 开始不允许使用后者反正更多。

齐心协力:没有成功。现在我必须通过KV访问Foo对象,这有点尴尬。

有人解决了这个问题吗?

编辑:添加代码以显示创建和向下转换。我遇到了 Xcode 7.0 的问题,现在和 7.1.1 一样

【问题讨论】:

  • 您能说明一下您是如何获取它的以及您是如何向下转换它的吗?
  • 您尝试过stackoverflow.com/questions/25076276/…stackoverflow.com/questions/26613971/… 中的各种解决方案吗?这是否发生在您的主程序或单元测试或框架中?
  • 我实际上正在处理一个包含核心数据的项目,并且我没有任何问题:self.entry = NSEntityDescription.insertNewObjectForEntityForName(entityName, inManagedObjectContext: managedObjectContext) as? Foo。你能发布更多细节吗?
  • @mad_manny,完成。这非常简单。
  • @MartinR,所有这些可能性都经过了测试。有或没有模块,它发生在主程序和测试中。

标签: swift core-data nsmanagedobject downcast


【解决方案1】:

看来主要问题是目标。感谢 Martin R 指出我的问题。 问题是,主应用程序中的代码也是部分或另一个目标,类似于测试。当从 Core Data 中检索对象时,它的类签名是 Target.Foo,如果您尝试将其转换为 Target2 中的 Foo,则会收到错误消息从Target.FooTarget2.Foo 是不可能的,不幸的是,除非日志为空,否则此消息不会显示在日志中?

完全没有关系,如果在下面的设置中,你如何命名类或模块:

唯一重要的是您的 .xcmod​​el 与访问它的代码位于同一目标中。

【讨论】:

    【解决方案2】:

    您需要编辑数据模型配置以告诉 CoreData 为特定实体使用哪个类。实际的实体名称本身对实例化的类没有影响。

    【讨论】:

    • 是的,这当然完成了。问题是返回的类不是 Foo,而是 Module.Foo,因此向下转换不成功。
    • 您应该使用“.Foo”(开头的点)而不是明确指定模块。它将在构建时确定。然后NSEntityDescription.insertNewObjectForEntityForName(entityName: String, inManagedObjectContext context: NSManagedObjectContext) 应该可以工作
    【解决方案3】:

    你需要在你的类中添加objc注解:

    @objc(Foo)
    class Foo: NSManagedObject {
       ...
    }
    

    【讨论】:

    • 试过了。没有帮助。不过,我相信如果你从 NSObject 或子类继承,@objc 指令是不需要的,它应该被推断出来。
    • 在我的情况下这是需要的,我已经扩展了 NSManagedObject。
    • 如果您将实体的模块设置为“当前产品模块”,那么您必须添加@objc(...),至少这是我所经历的。
    【解决方案4】:

    你需要直接实例化 Foo-Class:

    let createdManagedObject = Foo(entity: entity!, insertIntoManagedObjectContext: managedObjectContext)
    

    如果您仍然想封装代码来管理 CoreData,您可以执行类似以下的操作:

    static func newInstanceForEntityName(name: String, context: NSManagedObjectContext) -> NSManagedObject {
    
        let anyType: AnyObject.Type = NSClassFromString(name)!
        let nsmType: NSManagedObject.Type = anyType as! NSManagedObject.Type
    
        let entity = NSEntityDescription.entityForName(name, inManagedObjectContext: context)
    
        return nsmType.init(entity: entity!, insertIntoManagedObjectContext: context)
    }
    

    你可以像这样使用它:

    let foo = newInstanceForEntityName("Foo", context: context) as! Foo
    

    【讨论】:

    • 这实际上是这样的,我在另一堂课上是如何做到的,但感谢您展示这一点! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多