2009-07-27 11 views
23

私はCocoa:列挙型キーによる辞書?

  • キーが
  • 値はNSObject

NSDictionaryのいくつかのサブクラスが(列挙型がNSCopyingに準拠していないここでは動作しませんされている列挙型です辞書/ハッシュマップを作成する必要があります)。

私はおそらくここでCFDictionaryRefを使用することができますが、これを実現する方法が他にあるかどうかを知りたいと思います。

答えて

29

enumsは整数なので、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]; 
+0

ありがとうございます!それは絶対にうまくいった:) – PlagueHammer

7

enums don't conform to NSCopying

これは控えめな表現です。列挙型はオブジェクトではないので、何にも適合しません。それらは整数と互換性のある基本的なCの値です。それがキーとして使用できないのは、それが本当の理由です。 NSDictionaryのキーと値はオブジェクトである必要があります。しかし列挙型は整数なので、それらをNSNumberオブジェクトにラップすることができます。これはおそらく最も簡単なオプションです。

列挙型が0から数に連続している場合(つまり、手動で値を設定しなかった場合)は、NSArrayを使用できます。インデックスはキーの列挙型の値を表します。 (いずれも「行方不明」のエントリがNSNullで満たさなければならない。)VoidPointerの提案で

28

、列挙型が-fshort-enumsがプレイしているときなど、整数(ではないことが判明したときにそれらの時のためにNSValueを使用する方であってもよいし、おそらくFoundationとの互換性を失うことはないでしょう)。

ずっとここで追加しようとしていますが、テクニック「私はコレクションクラスに非にObjCタイプ>の<名前を使いたい」の一般提供していない
NSValue *value = [NSValue value: &myEnum withObjCType: @encode(enum ETest)]; 

現代のコンパイラでは、enums to use a fixed underlying typeと言うことができます。つまり、列挙型に使用するストレージを制御できますが、上記の解決策は一般的なので、これを知っていても適用されます。

+0

ニース、これは確かにNSValueがそこにあるのと同じくらい良いフィット感です。 NSValueはintに指された値をコピーしますか? – VoidPointer

+0

OK、http://cocoadev.com/forums/comments.php?DiscussionID=1169&page=1にコピーがあります:) – VoidPointer

+0

UIKeyboardTypeをNSValueに変換することを提案していますが、エラー:http://stackoverflow.com/questions/6130315/how-to-add-a-method-to-uitextfield-uitextview/6132880#6132880 – ma11hew28

9

さらにあなたはあなた以外NSObjectのタイプのキーと値を追加することができますNSMutableDictionaryにメソッドを追加するために、Objective-Cのcategoryを使用することができます...グラハム・リーからの提案に

を拡張。これにより、コードはラップ/アンラッピング構文から解放されます。再び

、まず、我々はNSValueにコンストラクタを説得追加している

enum ETest { FOO, BAR }; 

を仮定:

@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

@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 
'を列挙ETEST' サポートを追加します

したがって、元の例は、

0に変換することができます。
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 
[dict setObject: @"Bar!" forETest:BAR]; 
NSLog(@"getting value Bar -> %@", [dict objectForETest: BAR]);  
[dict release]; 

辞書にアクセスするためのenumの使用量によっては、コードの可読性がかなり低下する可能性があります。

+0

です。ピンポン:-)。 +1 NSValueカテゴリの場合、私は個人的にNSMutableDictionaryカテゴリを使用しませんでした。なぜオブジェクトをキーとして渡さなかったのか、私は絶えず疑問に思います。そして、なぜ私は '' [NSDictionary objectForetest:] 'を呼び出せなかったのですか?:/ –

+0

少なくとも、ある種のプリミティブ、つまり' 'オブジェクトクラス ''の型を特定する方法があったらいいのに。それはボクシング/アンボクシングプロセスをより多くの生き生きとさせるだろう。 –

2

私はカテゴリアプローチも好きで、おそらく私の場合もこれを実装します。新しいリテラル/ボクシングの表現は、それが何であれ、@(FOO)を使用してボクシングの世話をするだろうか?

私はそう思っていますし、そうであれば、それをキーとして使用するときに明示的にボクシングすることによって非常に透過的に動作します。