2012-02-10 8 views
2

私は次のコードがあります:私はNSDictionaryNSMutableDictionaryのいずれかであるオブジェクトを持っている場合は、私が言うことができるか、だから(私はむしろ避けたい)tryブロックの短いiOS - NSDictionaryとNSMutableDictionaryを区別する

NSString* value = @"value"; 
NSString* key = @"key"; 
NSMutableDictionary* foo = [NSMutableDictionary dictionary]; 
NSDictionary* bar = [NSDictionary dictionary]; 
NSAssert([bar isKindOfClass: [NSMutableDictionary class]], @""); // passes the assert as both are NSCFDictionary; 
NSAssert([bar respondsToSelector: @selector(setValue:forKey:)], @""); // passes the assert because it NSCFDictionary does respond to the selector 
[foo setValue:value forKey:key]; // no problem, foo is mutable 
[bar setValue:value forKey:key]; // crash 

を差?

+1

-setObject:forKey :, -setValue:forKey:を使用しないことをお勧めします。 –

+0

辞書を持っていて、それが可変であるかどうかわからないという現実的な例がありますか? – bneely

+0

[bar respondsToSelector:@selector(setValue:forKey :)]が機能しないことを追加したかっただけです。 – picciano

答えて

3
NSAssert([bar isMemberOfClass: [NSMutableDictionary class]], @""); 
+2

iOS 6以降で動作します。 iOS 5.x以降では大したことはありません。それを覚えておいてください。 –

+0

ちょうど頭が上がっています。あなたがメインの中にいれば、これは失敗します。代わりにNSCAssertを使用してください。 – smileBot

+0

これは実際には間違っています。 https://www.bignerdranch.com/blog/about-mutability/ –

1

それはこのように、あなたがする必要があるすべては、クラスのメンバーに対するテストで、実際にはかなり簡単です:正直なところ

if ([bar isMemberOfClass:[NSMutableDictionary class]]){ 
    [bar setValue:value forKey: key]; 
} 

iPhone SDK difference between isKindOfClass and isMemberOfClass

+0

残念ながら、これは実際には機能しません。これはクラスクラスタで、OPが指摘するように、ここでは '__NSCFDictionary'を得ることができます。これはこのテストに失敗します。 –

+0

私がショーを指しているように、OPが例として書いたものと私が書いたものとの間には違いがあります。 OPは 'isKindOfClass:'でクラスの等価性をチェックします。ここで 'isMemberOfClass:'でチェックします。私はそれをテストしていませんが、barが 'NSDictionary'ならば' false'になります。より良い説明のためにこのリンクを参照してください:http://stackoverflow.com/a/3653948/267892 – Emil

+0

おそらく、あなたはそれをテストする必要があります。 :)これはうまくいきません。メンバーシップテストはNSDictionaryとNSMutableDictionaryの両方で失敗します。どちらも検査対象の実際のクラスではないからです。 –

5

、あなたは簡単にすることなく、違いを見分けることはできません@tryブロック。次のように標準的な方法は次のとおりです。

  • あなたはそれが誰かあなたに予期せず変更可能なオブジェクトを渡した後、あなたの下からそれを変異さを避けるために、変更可能なのかどうか確認したい場合は、copy辞書。それが実際に変更可能でない場合、フレームワークはそれをretainに最適化します。実際にであった場合は、おそらくコピーが必要でした。
  • 変更可能な辞書が必要な場合は、メソッドのパラメータを宣言してそれを要求します。そのような単純な。
  • 一般に、変更可能であると特に言わない限り、人々はオブジェクトを変異させようとはしません。
0

あなたは辞書は変更可能であることを保証する必要がある場合は、あなたがすべき:

  • あなたは
  • それを初期化させた場合はどうで変更可能なインスタンスにそれを回すように変更可能な、それを作成します - [NSDictionary mutableCopy]メソッド。たとえば、NSDictionaryを返すAPIを呼び出す場合です。 mutableCopyは保持カウントをインクリメントすることに注意してください。手動参照カウントを使用している場合は、このインスタンスを解放する必要があります。 NSDictionaryのは、そのキーおよび/または値を変更する前に、変更可能であるかどうかを決定

は、解決すべき深い問題があることを示す、code smellの一例と考えることができます。言い換えれば、与えられた辞書インスタンスがNSDictionaryかNSMutableDictionaryかを常に知っておくべきです。その点でコードは明確でなければなりません。

+0

理論的にはいいですが、実際にはこれらの状況が発生します。たとえば、ある配列でobjectAtIndex:を呼び出すか、ある辞書でvalueForKey:を呼び出して取得したとします。さて、あなたが私が配列に入れたものを慎重にすべきだと言うかもしれません。それは良い理論ですが、私がこれらの小切手を入れたくないためにクラッシュする出荷コードはオプションではありません。 –

+0

あなたはいつも知ることはできません。たとえば、単体テストを書くときには、実際に知っていても、メソッドから返されたオブジェクトが期待通りのものであることを確認することは良い考えです。 – Caleb

0

あなたは本当にそれが可変かどうケア、とにかくそれを変異させたくない場合、あなたはこの試みることができる:

NSString* value = @"value"; 
NSString* key = @"key"; 

NSDictionary* bar = [NSDictionary dictionary]; 
NSLog(@"bar desc: %@", [bar description]); 
NSMutableDictionary* temp = [bar mutableCopy]; 
[temp setValue:value forKey:key]; 
bar = temp; 
NSLog(@"bar desc: %@", [bar description]); 
0

を私は@tryキャッチを使用して終了しかし、それは一度だけ発生させます。したがって、このように動作します

NSMutableDictionary *valuesByIdMutable = (id)self.valuesById; 

simplest_block block = ^{ 
    [valuesByIdMutable setObject:obj forKey:key]; 
}; 

@try { 
    block(); 
} @catch (NSException *exception) { 
    self.valuesById = valuesByIdMutable = [valuesByIdMutable mutableCopy]; 
    block(); 
} 
関連する問題