lukas_o
lukas_o

Reputation: 4236

NSDictionary (__NSDictionaryI) isMemberOfClass: isKindOfCLass: difference

I understand the difference between isKindOfClass: and isMemberOfClass: but I came across something I do not understand:

-(UIImage *)doSomething:(id)item 
{

    UIImage *image;

    if ([item isKindOfClass:[NSDictionary class]]) {
        NSDictionary *dictionary = item;
        NSData *data = [dictionary objectForKey:@"image"];
        image = [[UIImage alloc] initWithData:data];
    } else { // if item is UIImage
        image = item;
    }

    return image;
}

If I am using isKindOfClass in this context everything works as expected. If I use isMemberOfClass I get the following crash asking for the size of the image later:

-[__NSDictionaryI size]: unrecognized selector sent to instance 0x123456

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionaryI size]: unrecognized selector sent to instance 0x123456'

I read other posts like this one but I couldn't find anything that would come closer.

Upvotes: 2

Views: 1747

Answers (1)

David Rönnqvist
David Rönnqvist

Reputation: 56625

Yes they are different and their difference is documented. Using isKindOfClass: will return YES for subclasses whereas isMemberOfClass: won't. Since NSDictionary is a class cluster (uses private subclasses internally) will get different results when using the two (because the instance would be a private subclass (in your case __NSDictionaryI).

When using isMemberOfClass:, this is what happens in your case:

  1. The argument item is a private dictionary subclass
  2. Evaluating isMemberOfClass: returns NO
  3. The dictionary is assigned to a UIImage variable
  4. The UIImage variable is returned (but it really contains a dictionary)
  5. You try and use that "image" and when the system asks for the image size, the dictionary doesn't respond to size and throws an exception.

Upvotes: 4

Related Questions