代码之家  ›  专栏  ›  技术社区  ›  Debajit

cocoa:带枚举键的字典?

  •  23
  • Debajit  · 技术社区  · 15 年前

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

    • 密钥是枚举
    • 值是 NSObject

    NSDictionary 这里不工作(枚举不符合 NSCopying )

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

    5 回复  |  直到 12 年前
        1
  •  29
  •   VoidPointer    15 年前

    由于枚举是整数,因此可以将枚举包装为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
  •  28
  •   user23743    12 年前

    对于voidpointer的建议,最好使用 NSValue 当枚举结果不是整数时(例如当 -fshort-enums 在游戏中,你应该永远不会打破与基金会的兼容性。

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

    这不会在这里增加太多内容,但会提供一般的“我想在集合类中使用非objc类型的<名称”技术。

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

        3
  •  9
  •   VoidPointer    15 年前

    进一步扩展了格雷厄姆·李的建议…

    你可以用目标-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添加“enum 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];
    

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

        4
  •  7
  •   newacct    15 年前

    枚举不符合nscopying

    这是一种轻描淡写的说法;枚举不“符合”任何事物,因为它们不是对象;它们是可以与整数互换的原始C值。这就是它们不能用作钥匙的真正原因。关键和价值观 NSDictionary 需要成为对象。但是由于枚举是整数,所以可以将它们包装成 NSNumber 物体。这可能是最简单的选择。

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

        5
  •  2
  •   FrostyL    12 年前

    我也喜欢类别方法,并且可能在我的案例中也会实现这一点。有了新的文字/拳击表达,不管它叫什么,你会用@(foo)来照顾拳击吗?

    我认为,如果是这样的话,当使用枚举作为键时,通过显式地对它进行装箱,它将非常透明地工作。