Подтвердить что ты не робот

Cocoa: Словарь с ключами перечисления?

Мне нужно создать словарь /hashmap, где

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

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

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

4b9b3361

Ответ 1

Так как перечисления являются целыми числами, вы можете обернуть перечисление в 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]; 

Ответ 2

С предложением VoidPointer лучше использовать NSValue для тех случаев, когда перечисления оказываются не целыми (например, когда -fshort-enums находится в игре, что никогда не должно быть так, как вы, вероятно, нарушаете совместимость с Фонд).

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

Это не собирается добавлять много здесь, но дает вам общее "Я хочу использовать < имя метода non-ObjC type > в методе коллекционного класса.

Обратите внимание, что с современными компиляторами вы можете указать enums использовать фиксированный базовый тип. Это означает, что вы можете контролировать, какое хранилище используется для перечисления, но поскольку это решение является общим, оно все равно применяется, даже если вы это знаете.

Ответ 3

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

Вы можете использовать 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];

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

Ответ 4

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

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

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

Ответ 5

Мне также нравится подход к категории, и, вероятно, это будет реализовано и в моем случае. С новыми выражениями "Литералы/бокс", что бы они ни называли, использовало бы @(FOO) заботиться о боксе для вас?

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