【问题标题】:Cocoa: Dictionary with enum keys?Cocoa:带有枚举键的字典?
【发布时间】:2010-11-14 07:11:19
【问题描述】:

我需要创建一个字典/哈希图,其中

  • 键是枚举
  • 值是NSObject 的某个子类

NSDictionary 在这里不起作用(枚举不符合NSCopying)。

我也许可以在这里使用CFDictionaryRef,但我想知道是否有其他方法可以实现这一点。

【问题讨论】:

    标签: objective-c cocoa dictionary enums hashtable


    【解决方案1】:

    由于枚举是整数,因此您可以将枚举包装在 NSNumber 中。当您向地图添加/检索某些内容时,您会将枚举传递给 NSNumber 构造函数...

    假设你有一个像...这样的枚举

    enum ETest {
        FOO, BAR
    };
    

    你可以像这样在 NSDictionary 中使用它...

    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
    [dict setObject: @"Foo!" forKey:[NSNumber numberWithInt: FOO]];
    NSLog(@"getting value for FOO -> %@", 
          [dict objectForKey: [NSNumber numberWithInt: FOO]]);  
    [dict release]; 
    

    【讨论】:

      【解决方案2】:

      根据 VoidPointer 的建议,在枚举结果不是整数的情况下使用 NSValue 可能会更好(例如当 -fshort-enums 发挥作用时,这不应该因为您可能会破坏与基金会)。

      NSValue *value = [NSValue value: &myEnum withObjCType: @encode(enum ETest)];
      

      这里不会增加太多内容,但会为您提供一般的“我想在集合类中使用 ”技术。

      请注意,使用现代编译器您可以告诉enums to use a fixed underlying type。这意味着您可以控制用于枚举的存储空间,但由于上述解决方案是通用的,即使您知道这一点,它仍然适用。

      【讨论】:

      • 很好,这确实更合适,因为它正是 NSValue 的用途。 NSValue 是否复制指向 int ctor 的值?
      • 我正在按照您的建议将 UIKeyboardType 转换为 NSValue,但出现错误:stackoverflow.com/questions/6130315/…
      • @MattDiPasquale - 您正在用 @encode(enum UIKeyboardType) 替换 @encode(enum ETest) 对吗?类型不仅由编译器标志确定,而且还可以根据枚举值本身的范围而变化(尤其是在有符号和无符号之间)。
      【解决方案3】:

      进一步扩展 Graham Lee 的建议...

      您可以使用objective-c category 向NSMutableDictionary 添加一个方法,该方法允许您使用非NSObject 类型的键添加值。这使您的代码免受包装/展开语法的影响。

      再次假设

      enum ETest { FOO, BAR };
      

      首先,我们向 NSValue 添加一个说服构造函数:

      @interface NSValue (valueWithETest)
      +(NSValue*) valueWithETest:(enum ETest)etest; 
      @end
      
      @implementation NSValue (valueWithETest)
      +(NSValue*) valueWithETest:(enum ETest)etest
      {
          return [NSValue value: &etest withObjCType: @encode(enum ETest)];
      }
      @end
      

      接下来我们将为 NSMutableDictionary 添加“枚举 ETest”支持

      @interface NSMutableDictionary (objectForETest)
      -(void) setObject:(id)anObject forETest:(enum ETest)key;
      -(id) objectForETest:(enum ETest)key;
      @end
      
      @implementation NSMutableDictionary (objectForETest)
      -(void) setObject:(id)anObject forETest:(enum ETest)key
      {
          [self setObject: anObject forKey:[NSValue valueWithETest:key]];
      }
      -(id) objectForETest:(enum ETest)key
      {
          return [self objectForKey:[NSValue valueWithETest:key]];
      }
      @end
      

      因此可以将原始示例转换为

      NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
      [dict setObject: @"Bar!" forETest:BAR];
      NSLog(@"getting value Bar -> %@", [dict objectForETest: BAR]);      
      [dict release];
      

      根据您使用枚举访问字典的次数,这可能会大大降低代码的可读性。

      【讨论】:

      • 是时候停止回答乒乓球了 :-)。 +1 为 NSValue 类别,但我个人不会使用 NSMutableDictionary 类别。我会一直想知道为什么我没有将对象作为键传递。以及为什么我不能打电话给-[NSDictionary objectForETest:] :-/
      • 我希望至少有一种方法可以识别某些 /any 原语的“类型”,比如[object class]。这将使装箱/拆箱过程更加宜居。
      【解决方案4】:

      枚举不符合 NSCopying

      这是轻描淡写的;枚举不“符合”任何东西,因为它们不是对象;它们是可与整数互换的原始 C 值。这就是它们不能用作键的真正原因。 NSDictionary 的键和值需要是对象。但由于枚举是整数,您可以将它们包装到 NSNumber 对象中。这可能是最简单的选择。

      另一个选项,如果枚举从 0 到某个数字是连续的(即您没有手动设置任何值),您可以使用NSArray,其中索引表示键枚举的值。 (任何“缺失”的条目都必须填写NSNull。)

      【讨论】:

        【解决方案5】:

        类别方法有其自己的用途,但较新的盒装表达式(例如@(FOO))应该为您处理类型转换。它通过在将枚举用作键时显式装箱来非常透明地工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-12-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-29
          相关资源
          最近更新 更多