Какао: Словарь с перечислимыми ключами?

Я должен создать dictionary/hashmap где

  • Ключи являются перечислениями
  • Значения являются некоторым подклассом NSObject

NSDictionary не будет работать здесь (перечисления не соответствуют NSCopying).

Я мог, возможно, использовать a CFDictionaryRef здесь, но я хотел бы знать, там ли какой-либо другой способ достигнуть этого.

24
задан Rui Peres 20 August 2012 в 08:43
поделиться

4 ответа

Поскольку перечисления являются целыми числами, вы можете обернуть перечисление в 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]; 
30
ответ дан 28 November 2019 в 22:23
поделиться

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

28
ответ дан 28 November 2019 в 22:23
поделиться

Дальнейшее расширение предложения Грэма Ли ...

Вы можете использовать категорию objective-c , чтобы добавить метод в NSMutableDictionary, который позволяет вам добавьте значение с ключом вашего типа, отличного от NSObject. Это избавляет ваш код от синтаксиса упаковки / развертывания.

Опять же, предполагая

enum ETest { FOO, BAR };

Сначала мы добавляем конструктор convince в 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

Затем мы добавим поддержку enum 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];

. В зависимости от того, сколько вы используете перечисление для доступа к словарю, это может немного облегчить читаемость вашего кода.

9
ответ дан 28 November 2019 в 22:23
поделиться

перечисления не соответствуют NSCopying

Это преуменьшение; перечисления ни с чем не «согласуются», поскольку они не являются объектами; это примитивные значения C, которые взаимозаменяемы с целыми числами. Это настоящая причина, по которой их нельзя использовать в качестве ключей. Ключи и значения NSDictionary должны быть объектами. Но поскольку перечисления являются целыми числами, их можно просто обернуть в объекты NSNumber . Это, вероятно, самый простой вариант.

Другой вариант, если перечисления непрерывны от 0 до некоторого числа (т.е. вы не устанавливали никаких значений вручную), заключается в том, что вы можете использовать NSArray , где индекс представляет значение ключевого перечисления. (Любые «отсутствующие» записи должны быть заполнены NSNull .)

7
ответ дан 28 November 2019 в 22:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: