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 

所以,如果我有一个NSDictionaryNSMutableDictionary的对象,缺less一个尝试块(我宁愿避免),我怎么能区分?

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

老实说,没有一个@try块就不能轻易分辨出区别。 标准做法如下:

  • 如果你想检查它是否可变,以避免有人通过你一个意外的可变对象,然后从你下面突出它, copy字典。 如果它真的是不可变的,框架将优化成retain 。 如果它真的可变的,那么你可能想要一个副本。
  • 如果你需要一个可变的字典,声明你的方法参数需要一个。 就那么简单。
  • 一般来说,相信人们不会试图改变对象,除非明确告诉他们是可变的。

实际上这很简单,你只需要testing一下类的成员就可以了:

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

iPhone SDK与isKindOfClass和isMemberOfClass之间的区别

如果你需要保证字典是可变的,你应该:

  • 如果你是一个初始化它创build它为可变的
  • 使用 – [NSDictionary mutableCopy]方法将其变成一个可变实例,例如,如果您正在调用返回NSDictionary的API。 请注意,mutableCopy递增保留计数; 如果使用手动引用计数,则需要释放此实例。

在尝试修改键和/或值之前确定NSDictionary是否是可变的,可以被认为是代码异味的一个例子,表明有一个更深层次的问题需要解决。 换句话说,你应该总是知道给定的字典实例是NSDictionary还是NSM​​utableDictionary。 代码应该清楚。

如果你真的不在乎它是否可变,而是想要改变它,你可以试试这个:

 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]); 

我最终使用@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(); }