views:

2701

answers:

3

Here's a small test program I wrote:

#import <Foundation/Foundation.h>

int main(int argc, char **argv) {   
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSArray *arr = [NSArray array];
    printf("Arr isMemberOfClass NSArray: %d\n", [arr isMemberOfClass:[NSArray class]]);
    printf("Arr isKindOfClass NSArray: %d\n", [arr isKindOfClass:[NSArray class]]); 

    [pool release];
    return 0;
}

And its output:

$ ./ismemberof   
Arr isMemberOfClass NSArray: 0   
Arr isKindOfClass NSArray: 1

How useful is the -isMemberOfClass: method in any of the Foundation classes? I understand this might give the desired results for classes which I subclass, but as for Foundation classes -- I find that a result of false for my arr variable is non-intuitive. Is the reason this happens because NSArray is not a concrete class but instead an abstract class, and underneath the hood NSArray is really a concrete instance of NSCFArray?

+2  A: 

I've never used -isMemberOfClass: myself, because if I've added functionality to an existing class it's usually been through adding methods, so -respondsToSelector: has given me what I need. On the other hand I can see how wanting to know which specific class you're looking at (an instance of) may be useful. For instance if you're dealing with an NSConstantString or NSSimpleCString you may be more willing to make assumptions regarding -fastestEncoding than you might be with instances of other classes.

To answer the question in the body, yes you're correct. The NSArray is implemented as a class cluster, so you will not see an object which isMemberOfClass: [NSArray class]. That doesn't make -isMemberOfClass: meaningless, it just means it's never true for NSArray.

Graham Lee
+6  A: 

You generally want isKindOfClass:, not isMemberOfClass:. The difference is that isKindOfClass: will return YES if the receiver is a member of a subclass of the class in question, whereas isMemberOfClass: will return NO in the same case.

As Graham Lee points out, NSArray is a class cluster. That means that every NSArray instance is actually an instance of some subclass—hence your findings. Only isKindOfClass: is useful for class-membership testing with class clusters.

That said, you generally should use respondsToSelector: rather than class-membership testing. One example would be objectEnumerator, which is also implemented by NSSet and NSDictionary (both of those also being class clusters). An exception would be plist serialization: sets aren't property lists, so you'd need to send allObjects to your set to get an array before trying to make plist data from it.

Peter Hosey
+1  A: 

The -isMemberOfClass: is useful when you're implementing the -isEqual: method in your own classes. If you have a class like this:

@interface Person : NSObject {
    NSString *name;
    NSUInteger age;
}
@property(copy) NSString *name;
@property(assign) NSUInteger age;
@end

And you want two Person objects to be deemed identical if they have the same name and age, you have to implement -isEqual:, and the -hash method from the NSObject: protocol:

- (BOOL)isEqual:(id)obj {
    return [obj isMemberOfClass:[self class]]
        && [obj name] == self.name
        && [obj age] == self.age;
}

- (NSUInteger)hash {
    return [self.name hash] + age;
}

PS: why use [obj isMemberOfClass:[self class]] rather than simply [obj class] == [self class]? It doesn't matter much in the code above, but it becomes important when you're dealing with more complex code that makes use of NSProxy. The isMemberOfClass: method will ask the object the proxy is standing in for if it is a member of that class, which is probably what you want.

Stig Brautaset