user1366911 user1366911 - 6 months ago 47
Swift Question

NSMutableDictionary isKindOfClass NSDictionary is false

Why is the following code snippet ONLY printing blah3 and blah4, but not blah2?

is supposed to respect inheritance, but it appears to be failing exactly that.


NSDictionary *dict = [NSDictionary new];
NSMutableDictionary *mutableDict = [NSMutableDictionary new];

if([dict isKindOfClass:[mutableDict class]]){
NSLog(@"blah"); //does not print (as expected)

if([mutableDict isKindOfClass:[dict class]]){
NSLog(@"blah2"); //does not print (unexpected!)

if([mutableDict isKindOfClass:[mutableDict class]]){
NSLog(@"blah3"); //prints

if([dict isKindOfClass:[dict class]]){
NSLog(@"blah4"); //prints


var dict = NSDictionary()
var mutableDict = NSMutableDictionary()
if(dict.isKindOfClass(mutableDict.dynamicType)) {print("blah")}
if(mutableDict.isKindOfClass(dict.dynamicType)) {print("blah2")}
if(dict.isKindOfClass(dict.dynamicType)) {print("blah3")}
if(mutableDict.isKindOfClass(mutableDict.dynamicType)) {print("blah4")}

Using Xcode 7.3.1, iOS 9.3.


The reason is, is not guaranteed to return an NSDictionary itself - it can return a subclass of it. And your dict happens to be of a subclass like NSDictionary0. Also, the mutable one is probably of a subclass of NSMutableDictionary, like NSMutableDictionaryM.

So your NSMutableDictionary is indeed a NSDictionary, but not it's not inheriting from that other subclass.

You can easily check with isKindOf:[NSDictionary class] instead. You might want to dump or inspect the classes of your concrete objects and be surprised.

Edit: here's a quick and dirty class diagram: enter image description here

As you can see, one is not "kind of" another, although both are NSDictionary.

This is called a "class cluster" and has some tricky implications. NSString is another famous one where the classes rarely are what newcomers expect.