[ACCEPTED]-In Objective-C, given an id, how can I tell what type of object it points to?-objective-c

Accepted answer
Score: 98

You can use isKindOfClass or isMemberOfClass

For example:

if ([foo isMemberOfClass:[NSBar class]])

0

Score: 89
[mysteryObject class]

will get you the class object. However, generally 2 you want to do something OOPy like check 1 for conformance to some protocol or interface.

Score: 54

In a dynamically typed language like Objective-C 35 (or Python or Ruby), you often don't want to 34 know what type of object it is. It's often 33 more productive to think of whether the 32 object responds to the message you wish 31 to send; if it does, you shouldn't care 30 what class it instantiates and if it doesn't 29 you must handle the case regardless of the 28 instance's type. This is known as "duck 27 typing"...if it quacks like a duck it is 26 a duck.

You can test whether an object responds 25 to a particular message (known as a selector 24 in Objective-C) like this:

if([mysteryInstance respondsToSelector:@selector(messageIWishToSend)]) {
  [mysteryInstance messageIWishToSend];
} else {
  //handle case where instance doesn't respond to the desired message
}

Even better than 23 testing for individual selectors is to define 22 a @protocol that describes the API you wish to use 21 for your classes:

// MyProtocol.h
@protocol MyProtocol
- (void)methodInMyProtocol;
@end

//MyClass.h

#import "MyProtocol.h"

@interface MyClass <MyProtocol> {

}
- (void)methodInMyProtocol;
@end

You can test whether an 20 instance implements the MyProtocol protocol like this:

if([mysteryInstance conformsToProtocol:@protocol(MyProtocol)]) {
  [mysteryInstance methodInMyProtocol];
} else {
  // ...
}

This 19 way of doing things is often uncomfortable 18 for folks coming from statically typed languages 17 like Java or C++. You loose the compiler 16 checking types for you. Dynamic typing makes 15 a great many things easier however, including 14 testing since you can easily replace an 13 instance with a fake at test time. Thus 12 the dynamic language approach is to test 11 more and worry about types less. You do 10 have good unit test coverage, don't you?

If 9 you really must determine the class of an 8 instance at run time (and you really probably 7 don't need to), you can use -[NSObject isKindOfClass:] to test whether 6 an instance is an instance of a class or 5 any of its subclasses or -[NSObject isMemberOfClass:] to test whether 4 an instance is an instance of a particular 3 class. You can inspect the Class object directly 2 as the return of -[NSObject class] and you can get the string 1 name of the instance's class with NSStringFromClass([mysteryInstance class]).

Score: 1

I found I had to cast back to id when used 7 with a method defined in a @protocol.

For 6 example, self.listeners is an array of id

If 5 I do this ....

for(id<PropertyListener> listener in self.listeners) {        
    if ( [ [ listener class]  respondsToSelector:@selector(propertyChanged:propertyName:)]) {

I get an error "No known instance 4 method for selector 'class'". Yet, when 3 I cast the id from id to id it works ... Why 2 I do not understand.

[ ((id)listener) class] respondsToSelector .... 

Here is the full 1 loop ...

for(id<PropertyListener> listener in self.listeners) {        
    if ( [ [ ((id)listener) class]  respondsToSelector:@selector(propertyChanged:propertyName:)]) {
        [listener propertyChanged: self propertyName:@"thePropName"];
    } else {
        [listener propertyChanged: self];
    }
}

More Related questions