Cocoa: Dictionary with enum keys?
Solution 1
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];
Solution 2
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.
Solution 3
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
.)
Solution 4
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.
Debajit
Updated on June 21, 2020Comments
-
Debajit almost 4 years
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 toNSCopying
).I could perhaps use a
CFDictionaryRef
here, but I'd like to know if is there any other way to achieve this.