【问题标题】:Object keys with NSMutableDictionary (Objective-C)带有 NSMutableDictionary 的对象键(Objective-C)
【发布时间】:2011-05-24 06:43:47
【问题描述】:

我想存储一堆键值对,键是我自己的对象 (ObjectA),它继承自 NSObject,值是一个 int。
我正在尝试使用 NSMutableDictionary。我了解您只能将对象类型存储在字典中,因此我有以下内容:

id value = [NSNumber numberWithInt:my_number];

[[self dictionary] setObject:value forKey:myObjectA];

现在这给了我一个错误,说

-[ObjectA copyWithZone:]: 无法识别的选择器发送到实例

这很好,我知道对象键需要实现 NSCopying 协议。然而我读到你可以通过使用 NSValue 包装你的对象来做到这一点。

谁能解释一下我将如何包装我的对象,以及如何通过键找到值?我仍然可以使用dictionary objectForKey:myObjectA 还是在搜索时也必须用 NSValue 对象包装 myObjectA ?或者我应该在我的自定义类上实现 NSCopying,还是使用字符串键?

我正在寻找这种使用字典的最简单和最简单的方法,如果必须,我将实现一个字符串键并使用 setValue:forKey: 代替,但如果可以的话,我宁愿使用对象键。

【问题讨论】:

    标签: objective-c nsdictionary key-value


    【解决方案1】:

    始终复制字典键。所以你只需要为你的类实现NSCopying协议,也就是copyWithZone:方法。

    此外,您应该为您的类实现isEqual: 方法。

    编辑:如何实现copyWithZone: 取决于许多因素(主要因素:深拷贝与浅拷贝)。请参阅 Apple 的 Implementing Object Copy 指南和 this SO answer

    【讨论】:

    • 您能否扩展您的答案以包括我将在我自己的类中的 copyWithZone 实现中放入的内容?
    • 如果实现-isEqual:,则需要实现-hash 如果-isEqual: 确定的两个对象相等,则它们必须具有相同的哈希值。
    【解决方案2】:

    您可以使用以下方法将 id 转换为 NSValue:

    NSValue* value = [NSValue valueWithNonretainedObject:object];
    ...
    id object_ = [value nonretainedObjectValue];
    

    但您需要管理字典之外的所有权。这将是一团糟。最好采用 NSCopying。


    还有第四个选项:使用CFDictionary,它允许对象只能被CFRetain/CFReleased,不能被复制。

    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
         kCFAllocatorDefault, 0,
         &kCFTypeDictionaryKeyCallBacks,
         &kCFTypeDictionaryValueCallBacks
    );
    
    ...
    
    CFDictionarySetValue(dict, myObjectA, value);
    ...
    
    CFRelease(dict);
    

    如果您正在为 Mac 或 iOS 6 及更高版本编程,请尝试使用 NSMapTable。

    NSMapTable* dict = [[NSMapTable mapTableWithStrongToStrongObjects] retain];
    ...
    [dict setObject:@"?" forKey:foo];
    ...
    [dict release];
    

    【讨论】:

    • 感谢您提供有关使用 NSValue 的提示。我不知道该实用程序,而这正是我所需要的。似乎是解决问题的更恰当的方法。
    【解决方案3】:

    在 iOS 6 中,您可以使用 NSMapTable (https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/NSMapTable_class/Reference/NSMapTable.html),它允许您为键和对象选择弱/强属性。

    【讨论】:

      【解决方案4】:

      你不需要使用 NSValue 来包装你的对象。你所拥有的将起作用,除非你错过了一块。对于 myObjectA 的类,您需要采用 NSCopying 协议(有关添加内容,请参阅the docs)。添加后,您在上面发布的代码应该可以正常工作。

      您可能需要考虑在您自己的对象上使用字符串作为键。如果要使用键值编码来访问它,则键必须是字符串。因此,如果您可以在使用字典的任何地方利用键值编码,那么使用字符串会让生活变得更轻松。

      【讨论】:

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