iOS — distinguish an NSDictionary from an NSMutableDictionary?

瘦欲@ 提交于 2020-01-11 10:44:05

问题


I have the following code fragment:

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

So if I have an object which is either an NSDictionary or an NSMutableDictionary, short of a try block (which I'd rather avoid), how can I tell the difference?


回答1:


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



回答2:


Honestly, you can't easily tell the difference without a @try block. Standard practice is as follows:

  • If you want to check whether it's mutable in order to avoid someone passing you an unexpectedly mutable object and then mutating it out from under you, copy the dictionary. If it's really non-mutable, the frameworks will optimize that into a retain. If it really was mutable, then you probably wanted a copy anyway.
  • If you need a mutable dictionary, declare your method parameters to require one. Simple as that.
  • In general, trust that people won't try to mutate objects unless specifically told they were mutable.



回答3:


It's pretty simple actually, all you need to do is test against the member of the class, like this:

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

iPhone SDK difference between isKindOfClass and isMemberOfClass




回答4:


If you need to guarantee that a dictionary is mutable, you should:

  • create it as mutable if you are the one initializing it
  • turn it into a mutable instance with the -[NSDictionary mutableCopy] method, for example if you're calling an API that returns an NSDictionary. Note that mutableCopy increments the retain count; you need to release this instance if you are using manual reference counting.

Determining whether an NSDictionary is mutable before attempting to modify its keys and/or values can be considered an example of a code smell, indicating that there's a deeper problem that should be solved. In other words, you should always know whether a given dictionary instance is NSDictionary or NSMutableDictionary. The code should be clear on that point.




回答5:


If you really don't care if it's mutable, but want to mutate it anyway, you could try this:

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



回答6:


I end up using @try catch but it only fires once. So it works like this

NSMutableDictionary *valuesByIdMutable = (id)self.valuesById;

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

@try {
    block();
} @catch (NSException *exception) {
    self.valuesById = valuesByIdMutable = [valuesByIdMutable mutableCopy];
    block();
}


来源:https://stackoverflow.com/questions/9235965/ios-distinguish-an-nsdictionary-from-an-nsmutabledictionary

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!