Cocoa:带有枚举键的字典?

发布于 2024-07-29 17:43:58 字数 231 浏览 3 评论 0原文

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

  • 键是枚举,
  • 值是 NSObject 的一些子类

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

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

I need to create a dictionary/hashmap where the

  • Keys are enums
  • Values are some subclass of NSObject

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

撕心裂肺的伤痛 2024-08-05 17:43:58

由于枚举是整数,因此您可以将枚举包装在 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]; 

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...

Assuming you've got an enum like...

enum ETest {
    FOO, BAR
};

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

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject: @"Foo!" forKey:[NSNumber numberWithInt: FOO]];
NSLog(@"getting value for FOO -> %@", 
      [dict objectForKey: [NSNumber numberWithInt: FOO]]);  
[dict release]; 
花落人断肠 2024-08-05 17:43:58

根据 VoidPointer 的建议,当枚举结果不是整数时(例如当使用 -fshort-enums 时,应该使用 NSValue 可能会更好)永远不要,因为你可能会破坏与基金会的兼容性)。

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

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

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

With VoidPointer's suggestion, it may be better to use NSValue for those times when enums turn out not to be integers (such as when -fshort-enums is in play, which should be never as you'd probably break compatibility with 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.

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.

耶耶耶 2024-08-05 17:43:58

进一步扩展 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 添加“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];

根据您使用枚举来访问字典的程度,这可能会缓解你的代码的可读性相当高。

Further extending on the suggestion from Graham Lee...

You could use an objective-c category in 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.

Again, assuming

enum ETest { FOO, BAR };

First, we're adding a convince constructor to 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

@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.

自控 2024-08-05 17:43:58

枚举不符合 NSCopying

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

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

enums don't conform to 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 NSDictionary need to be objects. But since enums are integers, you can just wrap them into NSNumber objects. This is probably the simplest option.

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 NSArray where the index represents the key enum's value. (Any "missing" entries would have to be filled with NSNull.)

吃兔兔 2024-08-05 17:43:58

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

The category approach has its own uses, but the newer boxed expressions (e.g. @(FOO)) should take care of type conversion for you. It works very transparently by explicitly boxing the enum when using it as a key.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文