【问题标题】:NSManagedObject as NSDictionary key?NSManagedObject 作为 NSDictionary 键?
【发布时间】:2010-12-02 15:04:40
【问题描述】:

在我的应用程序中,我有一个NSDictionary,其键应该是NSManagedObject 的子类的实例。

然而,问题是NSManagedObject 没有实现NSCopying 协议,这意味着即使-[hash] 方法适用于他们。

我应该这样做吗?

【问题讨论】:

    标签: cocoa core-data nsdictionary nscopying


    【解决方案1】:

    有四个选项:

    1. 改为使用不同的对象作为字典键,并从中查找。 [object objectID]+[NSValue valueWithNonretainedObject:] 似乎是最明显的
    2. 使用CFDictionaryCreateMutable()创建一个带有保留键的字典,而不是复制,然后调用CFDictionarySetValue()来存储对象
    3. 在 OS X 或 iOS6+ 上,[NSMapTable mapTableWithStrongToStrongObjects] 为您提供与 CFMutableDictionary 等效的纯 Objective-C
    4. 为您的托管对象子类实现 NSCopying,使其返回 self(如果您不使用 ARC,则引用计数会增加)

    注意事项

    +valueWithNonretainedObject: 非常危险,因为它可能会留下一个悬空指针;最好避免。

    存储对象 ID 很好,除了 new 对象以 临时 ID 开始生命。然后,当上下文保存到磁盘(或调用 -obtainPermanentIDsForObjects:…)时,该 ID 将更改为永久 ID。您的映射代码需要足够聪明才能处理这个问题,除非它可以保证所有传入的对象都已经有一个永久 ID。

    像这样实现NSCopying 感觉有点恶心,但应该可以正常工作。碰巧,这正是NSURLSessionTask 采用的方法,我认为是为了字典友好。

    在 OS X 10.8 Mountain Lion 之前,曾经可以创建一个常规的NSMutableDictionary,然后为它调用CFDictionarySetValue()。但情况已不再如此。新字典现在在 CF 级别向下指定了正确的复制回调,而不是纯粹是 NSMutableDictionary 的一个功能。

    【讨论】:

    • 我不会考虑选择 1 或 2。我发现当托管对象 ID INSTANCE 更改时,它会被视为不同的键。托管对象 ID 必须使用实例地址来计算从密钥对象派生的唯一值。我想知道 2 是否会通过消除密钥副本来解决问题。没有这样的运气。
    • @stephen 感谢您提示我更新答案
    • 您的知识深度表明您在研究上花费了大量时间。感谢更新。顺便说一句:我发表评论的动机有点极端:我一直在努力回应 NSManagedObjectContextObjectsDidChangeNotification
    • 为什么不在子类中实现 NSCopying?
    • 这是一个公平的观点。我觉得有点奇怪,但我看不出为什么不这样做的主要原因。我会把它添加到我的答案中
    【解决方案2】:

    我建议使用 [[[myManagedObject objectID] URIRepresentation] absoluteString] 作为您的密钥。

    【讨论】:

    • 这一切都毫无意义。 NSManagedObjectID 可以按原样使用,因为它实现了 NSCopying。
    • 有——您可以归档对象 ID 的 URIRepresentation(通过 NSCoding)。如果您想将 NSManagedObject 复制到粘贴板中,这非常有用。
    • 嗯,是的,但这里的重点是发布者想要构建一个由托管对象键入的字典;对我来说,这听起来不是粘贴板上的内容
    • 我认为还有更多。托管对象 ID 可以更改。它们最初是一个临时 ID,然后可能会变成一个永久 ID。如果您想消除这种潜在问题的情况,使用 URI 表示是可行的方法。
    • @MikeAbdullah 还有:NSManagedObjectID 引用 NSEntityDescription(通过其实体属性)。并且 NSEntityDescription 的文档指出 NSEntityDescriptions 不应该用作字典中的键:因为 NSDictionary 复制它的键并要求键既符合 NSCopying 协议并且具有 copy 返回一个对象的属性 [[object copy] isEqual :object] 是真的,你不应该使用实体作为字典中的键。
    【解决方案3】:

    您能否创建一个包装类,其中包含对您想用作字典键的 NSManagedObject 实例的引用?然后,您可以让这个包装类实现 NSCopying,以及一个散列方法(可能只是调用 NSManagedObject 的散列方法),并将这个包装类用作字典键。

    【讨论】:

      【解决方案4】:

      我遇到了类似的问题,我需要将多个实体与每个实体的附加数据捆绑在一起,最初尝试过:

      @{entity1:data1, @entity2:data2, @entity3:data3}
      

      由于上述原因(NSCopying),这不起作用,所以我做了:

      @[
         @{@"entity":entity1, @"data":data1},
         @{@"entity":entity2, @"data":data2},
         @{@"entity":entity3, @"data":data3}
      ]
      

      但只有当您不需要对这些实体进行字典式访问或乐于迭代以找到所需内容时,此解决方案才有意义。就我而言,这是一个包装问题。请注意,如果您在 NSManagedObjectContext 周围传递这些实体,则需要相同才能使用它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多