【问题标题】:Can I encode a subclass of NSManagedObject?我可以编码 NSManagedObject 的子类吗?
【发布时间】:2010-11-25 04:45:28
【问题描述】:

这是针对 iPhone 应用程序的,但我认为这并不重要。我需要使用 iPhone 的 GameKit 通过蓝牙发送一个自定义对象(由 Core Data 管理)。通常,我只会使用 NSKeyedArchiver 将对象打包为数据对象并将其传送到线路上,然后取消归档对象,我就完成了。当然,我还需要在我的自定义对象中实现 initWithCoder: 和 encodeWithCoder: 方法。

我不确定这是否可以使用由 Core Data 管理的 NSManagedObject 类来完成。他们会一起玩吗?我猜一旦我将编码的托管对象发送到另一个设备并取消编码,我只会将此接收到的对象添加到另一个设备的上下文中。它是否正确?我是否缺少任何步骤?

【问题讨论】:

    标签: iphone objective-c cocoa cocoa-touch core-data


    【解决方案1】:

    这听起来像是TPAutoArchiver 的工作。

    【讨论】:

      【解决方案2】:

      我建议使用字典解决方案以获得更简单的选项。但是,这是我解决问题的方法。我的模型已经相当大且健壮,具有自定义类和NSManagedObject 之上的单个根类。

      我所需要的只是让该单个类调用NSManagedObject:[super initWithEntity:insertIntoManagedObjectContext:] 的适当指定初始化程序。这个方法和NSEntityDescription 中的元数据是设置所有动态访问器的实现的原因。

      - (id)initWithCoder:(NSCoder *)aDecoder {
        CoreDataStack *cds = [LibraryDiscoverer unarchivingCoreDataStack];
        NSEntityDescription *entity = [cds entityDescriptionForName:[[self class] entityName]];
        NSManagedObjectContext *moc = [cds managedObjectContext];
        self = [super initWithEntity:entity insertIntoManagedObjectContext:moc];
        self.lastEditDate = [aDecoder decodeObjectForKey:@"lastEditDate"];
        return self;
      }
      

      CoreDataStack 是我对 CoreData 的抽象。 LibraryDiscoverer 是一个全局访问挂钩,用于获取核心数据信息。 entityName 是定义为从类名中提供实体名的方法;如果您遵循命名约定(即类名 = 实体名),则可以通用实现。

      我的类层次结构中的所有其他initWithCoder: 方法都是标准的NSCoder,请注意您不需要对关系的两个方向进行编码,CoreData 会为您重新连接。 (一如既往,包括字典解决方案。)

      【讨论】:

      • 不错的解决方案。当你有两个堆栈时,你将如何管理这个?我目前正在开发一个通过网络与应用程序的另一个实例通信的应用程序。在我的测试目标中,我有一个单元测试来测试通信。在这种情况下,我需要两个不同的堆栈。结合上面给出的示例,您将如何解决这个问题?
      • 我实际上创建了一个新的、唯一的堆栈来进行取消归档,然后保存上下文(主堆栈监听并更新),然后删除导入堆栈。 - - - 你可以保留 NSCoder 的映射 -> 如果你想要复杂的堆栈 unarchivingCoreDataStackForCoder:(NSCoder *)decoder
      【解决方案3】:

      NSManagedObject 实例不能有意义地存在于 NSManagedObjectContext 实例之外,因此我不会费心尝试在两个上下文之间直接序列化和反序列化 NSManagedObject 所需的 NSCoding 舞蹈(您可以做到这一点;见下文)。相反,我会创建一个具有适当属性键/值的字典(您可以通过托管对象实例的属性名称通过instance.entity.attributesByName.allKeys 获取属性名称(您可以使用[instance dictionaryWithValuesForKeys:keys] 来获取属性:值对的字典)。我会将关系信息发送为NSURL-编码NSManagedObjectIDs。不要忘记在字典中包含实例managedObjectID(作为NSURL),以便您可以重新连接任何关系另一端的对象。您必须为您正在编码的实例的任何关系目标递归地创建这些字典。

      然后通过网络发送 dict(s) 并在另一端将它们重组为新托管对象上下文中的实例(您可以使用 setValuesForKeysWithDictionary:)。

      您可能会注意到这正是NSCoder 系统将为您做的事情,除了您必须使用classForCoderreplacementObjectForCoder:awakeAfterUsingCoder: 以及自定义NSDictionary 子类来处理所有NSManageObject-to-NSDictionary 映射,反之亦然。根据我的经验,这段代码麻烦多多,除非你有一个复杂/深层次的对象图,你试图序列化。对于没有关系的单个 NSManagedObject 实例,将其转换为 dict 并返回自己肯定更容易。

      【讨论】:

      • 我遇到了同样的问题,我最终完全按照 Barry 的建议去做 - 效果很好。
      • 是否也可以代替 NSDictionary,我将拥有与我的 NSManagedObject 相同的模型?我会在那里做映射?
      • 谁能解释一下 NSURL 编码的 NSManagedObjectIDs 对人际关系有什么帮助?谢谢!
      • 太棒了!谢谢你(三年后)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-24
      • 1970-01-01
      • 2020-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多