2009-07-27 101 views
23

我需要创建一个字典/ HashMap的其中可可:带有枚举键的字典?

  • 键是枚举
  • 数值为NSObject一些子类

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

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

回答

29

由于枚举是整数,所以可以将枚举包装在一个NSNumber中。当您添加/ retreive到/从地图上看,你通过枚举到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]; 
+0

谢谢!这工作绝对好:) – PlagueHammer 2009-07-28 04:09:46

7

enums don't conform to NSCopying

这是一个保守的;枚举不“符合”任何事物,因为它们不是对象;它们是可与整数互换的原始C值。这就是为什么他们不能用作钥匙的真正原因。 NSDictionary的键和值需要是对象。但由于枚举是整数,所以可以将它们包装为NSNumber对象。这可能是最简单的选择。

另一种选择是,如果枚举从0到某个数字连续(即没有手动设置任何值),则可以使用NSArray,其中索引代表键枚举的值。 (任何“遗漏”项就必须充满NSNull

28

随着VoidPointer的建议,它可能是更好的使用NSValue对于那些时候,枚举变成不为整数时(如-fshort-enums是在玩,这应该永远不会像你可能会破坏与基金会的兼容性)。

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

那不是要在这里多添加,但给你一般的“我想在集合类使用非ObjC型>的<名”技术。

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

+0

不错,这确实是一个更好的适合,因为它正是NSValue的。 NSValue是否将指向int的值复制到ctor? – VoidPointer 2009-07-27 13:29:26

+0

好吧,http://cocoadev.com/forums/comments.php?DiscussionID=1169&page=1表示它确实复制:) – VoidPointer 2009-07-27 13:30:54

9

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

你可以使用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 

下一步,我们将添加 '枚举Etest法' 支持的NSMutableDictionary

@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]; 

取决于您使用enum访问字典的次数多少,这可能会让您的代码更容易阅读。

2

我也喜欢类别的方法,也可能会在我的情况下实现这一点。用新的Literals/boxing表达式,无论它叫什么,都会用@(FOO)来照顾你的拳击吗?

我认为它会,如果是这样,通过明确地装箱枚举使用它作为一个关键时非常透明。