In Objective-C, given an id, how can I tell what type of object it points to?
Objective-C newbie question. Given the following (fictional) code:
id mysteryObject = [anotherObject mysteriousMethod];
How can I determine at runtime what class mysteryObject
is?
You can use isKindOfClass
or isMemberOfClass
For example:
if ([foo isMemberOfClass:[NSBar class]])
[mysteryObject class]
will get you the class object. However, generally you want to do something OOPy like check for conformance to some protocol or interface.
In a dynamically typed language like Objective-C (or Python or Ruby), you often don't want to know what type of object it is. It's often more productive to think of whether the object responds to the message you wish to send; if it does, you shouldn't care what class it instantiates and if it doesn't you must handle the case regardless of the instance's type. This is known as "duck typing"...if it quacks like a duck it is a duck.
You can test whether an object responds to a particular message (known as a selector 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 testing for individual selectors is to define a @protocol
that describes the API you wish to use 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 instance implements the MyProtocol
protocol like this:
if([mysteryInstance conformsToProtocol:@protocol(MyProtocol)]) {
[mysteryInstance methodInMyProtocol];
} else {
// ...
}
This way of doing things is often uncomfortable for folks coming from statically typed languages like Java or C++. You loose the compiler checking types for you. Dynamic typing makes a great many things easier however, including testing since you can easily replace an instance with a fake at test time. Thus the dynamic language approach is to test more and worry about types less. You do have good unit test coverage, don't you?
If you really must determine the class of an instance at run time (and you really probably don't need to), you can use -[NSObject isKindOfClass:]
to test whether an instance is an instance of a class or any of its subclasses or -[NSObject isMemberOfClass:]
to test whether an instance is an instance of a particular class. You can inspect the Class
object directly as the return of -[NSObject class]
and you can get the string name of the instance's class with NSStringFromClass([mysteryInstance class])
.