2009-07-27 8 views
23

muszę stworzyć słownik/hashmap gdzieKakao: słownik z klawiszami enum?

  • klucze są wyliczenia
  • Wartości są niektóre podklasy NSObject

NSDictionary nie zadziała tutaj (teksty stałe nie są zgodne z NSCopying).

Mogę użyć tutaj CFDictionaryRef, ale chciałbym wiedzieć, czy jest jakikolwiek inny sposób, aby to osiągnąć.

Odpowiedz

29

Ponieważ wartości całkowite są liczbami całkowitymi, można zawrzeć wyliczenie w NSNumber. Po dodaniu/retreive coś do/z mapy, przejechania enum do konstruktora NSNumber ...

Zakładając masz enum jak ...

enum ETest { 
    FOO, BAR 
}; 

Można go używać w NSDictionary tak ...

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 
[dict setObject: @"Foo!" forKey:[NSNumber numberWithInt: FOO]]; 
NSLog(@"getting value for FOO -> %@", 
     [dict objectForKey: [NSNumber numberWithInt: FOO]]); 
[dict release]; 
+0

Dzięki! To działało absolutnie świetnie :) – PlagueHammer

7

enums don't conform to NSCopying

jest to mało powiedziane; wyliczenia nie "dostosowują się" do niczego, ponieważ nie są obiektami; są to prymitywne wartości C, które można stosować zamiennie z liczbami całkowitymi. To jest prawdziwy powód, dla którego nie można ich używać jako kluczy. Klucze i wartości NSDictionary muszą być obiektami. Ale ponieważ wyliczenia są liczbami całkowitymi, możesz po prostu je zawinąć w obiekty NSNumber. Jest to prawdopodobnie najprostsza opcja.

Inna opcja, jeśli wartości sąsiadujące są ciągłe od 0 do pewnej liczby (tj. Nie ustawiono żadnych wartości ręcznie), to można użyć wartości NSArray, w której indeks reprezentuje wartość wyliczenia klucza. (Wszelkie „brakujące” wpisy będą musiały być wypełnione NSNull.)

28

Z sugestią VoidPointer, może on być lepiej użyć NSValue dla tych czasów, kiedy teksty stałe okazują się nie być liczbami całkowitymi (na przykład gdy -fshort-enums jest w grze, co nigdy nie powinno być tak, jak prawdopodobnie złamiesz zgodność z Fundacją).

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

To nie będzie dodać dużo tutaj, ale daje ogólny „Chcę użyć < nazwę non-objc typu > w klasie kolekcja” techniki.

Zauważ, że w przypadku współczesnych kompilatorów możesz powiedzieć enums to use a fixed underlying type. Oznacza to, że możesz kontrolować, jakiego magazynu używasz do wyliczenia, ale ponieważ powyższe rozwiązanie jest ogólne, nadal obowiązuje, nawet jeśli wiesz o tym.

+0

Miło, to jest rzeczywiście lepsze dopasowanie, ponieważ jest to dokładnie to, co jest NSValue. Czy NSValue kopiuje wartość wskazywaną int ctor? – VoidPointer

+0

Ok, http://cocoadev.com/forums/comments.php?DiscussionID=1169&page=1 mówi, że robi kopię :) – VoidPointer

+0

Robię co sugerujesz, aby przekonwertować UIKeyboardType na 'NSValue', ale dostaję błąd: http://stackoverflow.com/questions/6130315/how-to-add-a-method-to-uitextfield-uitextview/6132880#6132880 – ma11hew28

9

Dalsze rozszerzenie na sugestię od Graham Lee ...

Można użyć objective-c category aby dodać metodę NSMutableDictionary, który pozwala na dodanie wartości z klucza swojego typu non NSObject . Dzięki temu twój kod nie będzie zawierał składanki do pakowania/rozpakowywania.

Ponownie zakładając

enum ETest { FOO, BAR }; 

Najpierw dodajemy konstruktora przekonać do 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 

Następny dodamy wsparcie '' ENUM Etest do 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 

Oryginalny przykład można przetransformować na

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

W zależności od tego, ile uzyskujemy, aby uzyskać dostęp do słownika, może to znacznie poprawić czytelność kodu.

+0

czas, aby zatrzymać odpowiedź na ping-ponga :-). +1 dla kategorii NSValue, ja osobiście nie użyłbym jednak kategorii NSMutableDictionary. Ciągle zastanawiałbym się, dlaczego nie przekazałem przedmiotu jako klucza. I dlaczego nie mogłem nazwać '- [NSDictionary objectForETest:]': -/ –

+0

Chciałbym, aby był przynajmniej sposób zidentyfikowania "typu" jakiegoś/dowolnego prymitywnego, á la '[klasy obiektu]'. sprawiłoby, że proces boksowania/rozpakowywania byłby o wiele bardziej żywy. –

2

Podobają mi się również podejścia kategorii i prawdopodobnie również w moim przypadku. Z nowymi wyrażeń Literals/boks, jakkolwiek by się nie nazywało, czy przy użyciu @ (FOO) zajmiesz się boksem?

Myślę, że tak, a jeśli tak, to działa bardzo przejrzyście, wyraźnie wyszczególniając wyliczenie, gdy używa się go jako klucza.