objective-c Cocoa:带有枚举键的字典?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1187112/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:58:41  来源:igfitidea点击:

Cocoa: Dictionary with enum keys?

objective-ccocoadictionaryenumshashtable

提问by PlagueHammer

I need to create a dictionary/hashmap where the

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

  • Keys are enums
  • Values are some subclass of NSObject
  • 键是枚举
  • 值是一些子类 NSObject

NSDictionarywon't work here (enums don't conform to NSCopying).

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

I could perhaps use a CFDictionaryRefhere, but I'd like to know if is there any other way to achieve this.

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

回答by VoidPointer

Since enums are integers, you can wrap the enum in an NSNumber. When you add/retreive something to/from the map, you pass the enum to the NSNumber constructor...

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

Assuming you've got an enum like...

假设你有一个像......

enum ETest {
    FOO, BAR
};

You can use it in an NSDictionary like this...

您可以像这样在 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]; 

回答by VoidPointer

With VoidPointer's suggestion, it may be better to use NSValuefor those times when enums turn out not to be integers (such as when -fshort-enumsis in play, which should be never as you'd probably break compatibility with Foundation).

根据 VoidPointer 的建议,最好NSValue在枚举不是整数的时候使用(例如-fshort-enums在播放时,这应该永远不会因为你可能会破坏与 Foundation 的兼容性)。

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

That's not going to add much here but gives you the general "I want to use <name of non-ObjC type> in a collection class" technique.

这不会在这里添加太多内容,但会为您提供一般的“我想在集合类中使用 <name of non-ObjC type>”技术。

Notice that with modern compilers you can tell enums to use a fixed underlying type. This means you can control what storage is used for the enum, but as the above solution is general it still applies even when you know this.

请注意,使用现代编译器,您可以告诉枚举使用固定的基础类型。这意味着您可以控制用于枚举的存储,但由于上述解决方案是通用的,即使您知道这一点,它仍然适用。

回答by VoidPointer

Further extending on the suggestion from Graham Lee...

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

You could use an objective-c categoryin order to add a method to NSMutableDictionary that allows you to add a value with a key of your non NSObject type. This keeps your code free from the wrapping/unwrapping syntax.

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

Again, assuming

再次,假设

enum ETest { FOO, BAR };

First, we're adding a convince constructor to NSValue:

首先,我们向 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

Next we'll add 'enum ETest' support to NSMutableDictionary

接下来,我们将向 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

The original Example can thus be transformed to

原始示例因此可以转换为

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

Depending on how much you use your enum to access the dictionary this may ease readability of your code quite a bit.

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

回答by newacct

enums don't conform to NSCopying

枚举不符合 NSCopying

This is an understatement; enums do not "conform" to anything as they are not objects; they are primitive C values which are interchangeable with integers. That's the real reason why they can't be used as keys. The keys and values of NSDictionaryneed to be objects. But since enums are integers, you can just wrap them into NSNumberobjects. This is probably the simplest option.

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

Another option, if the enums are contiguous from 0 up to some number (i.e. you didn't set any values manually), is that you can use an NSArraywhere the index represents the key enum's value. (Any "missing" entries would have to be filled with NSNull.)

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

回答by FrostyL

I like the category approach also and will probably implement this in my case also. With the new Literals/boxing expressions whatever it's called, would using @(FOO) take care of the boxing for you?

我也喜欢类别方法,并且可能也会在我的情况下实现这一点。使用新的文字/装箱表达式,不管它叫什么,使用 @(FOO) 会为您处理装箱吗?

I think it would and if so works very transparently by explicitly boxing the enum when using it as a key.

我认为它会并且如果是这样,通过在将枚举用作键时显式装箱它会非常透明地工作。