When I first learned Java, I thought the whole reflection package was novel, and it put Java closer to the realm of interpreted scripting language and farther away from the then-mainstream languages of C and C++. The idea of being able to look inward at the class metadata of an object at runtime was really fascinating, although not always terribly useful in everyday application programming.
Those programmers coming over to the Objective-C world from Java will be happy to know that Objective-C also supports the concepts of reflection, AKA introspection.
In fact, Objective-C 2.0 has many runtime features such as dynamically changing a class definition and even creating a new class dynamically. The necessity for these abilities is rather obscure, and it firms my belief that Objective-C is a ridiculously bloated language.
To me, Objective-C has a bit of an identity crisis: it's not quite sure if it's an interpreted language or a compiled language. The runtime is mostly dynamic. Unlike C++, Objective-C does runtime binding. This is why you can do things like define methods for an implementation that are never declared in your header file, or extend existing classes with categories.
Unfortunately, because of all this bloat, it is hard to find just the simple stuff that you might actually use in your day-to-day code. I will try to unearth some of these jewels and bring them to light.
Grandpa NSObject
Most, if not all, the runtime reflection support comes from the NSObject class. NSObject, like Java's Object class, is the granddaddy class of all classes (except for some rare exceptions). Therefore, all of your classes already have access to this reflection support.
It's important to note that all this reflection support is not part of the Objective-C language per se; it is part of the NS* runtime environment. This is also why some of this stuff seems tacked on. It's because it has, uh, been tacked on.
Getting Class Metadata
You can access the class metadata for an object by calling the
class method:
Class c = [self class];
This method is both an instance and a class method. It returns a C struct full of all sorts of mysterious stuff, like the list of instance variables, methods, etc. All of this is old hat to the java.lang.reflect package users out there, but the interfaces to reach this stuff in Objective-C seems really complex. This is probably difficult by design to keep the riff-raff out.
So far, the only use I have for the class method is to provide the parameter to the isKindOfClass method described below. I never need to actually look at the contents of the Class structure.
Dynamic Method Invocation
I already discussed one aspect of reflection in my article about
invoking methods. This allows you to build up a method call, arguments and all, at runtime. This is similar to using the java.lang.reflect.Method class in Java.
Testing inheritance
Java has an operator called
instanceof that allows you to check if a object is an instance of a particular class or interface. Objective-C has a similar feature, the
isKindOfClass: method.
isKindOfClass: will return YES if the receiver is an instance of the given class or an instance of any class derived from the class. For example, if I had an array of related pointers, I can operate on each differently according to its type:
for(BaseClass* base in myArray) {
if([base isKindOfClass:[ClassOne class]]) {
// do stuff specific to ClassOne
}
else if([base isKindOfClass:[ClassTwo class]]) {
// do stuff specific to ClassTwo
}
else if([base isKindOfClass:[ClassThree class]]) {
// do stuff specific to ClassThree
}
// etc
}
If you want an exact class match, and not match any inheriting classes, then you use
isMemberOfClass:.
Testing Protocol Conformance
Similar to class instance testing, you can also test whether an object conforms to a particular protocol. Java neatly uses
instanceof for both classes and interfaces, but Objective-C has to have a more clunkier approach. To test conformance, use the
conformsToProtocol: method:
BOOL conforms = [obj conformsToProtocol:@protocol(MyInterface)];
Testing for Method Existence
To an old Java and C++ hack like me, it seems extremely odd that you may not know if an object implements a method or not. But since Objective-C classes are largely dynamic, you need a way to check if a method you need is actually there. Hence the method
respondsToSelector:. Here you are asking the receiver if it implements (or inherits) the given method:
if([obj respondsToSelector:@selector(aMethod:)]) {
// it's there, so we can call it
[obj aMethod:YES];
}
Certainly, there is way more you can do on the reflection front in Objective-C, but I tried to discuss the more commonly used reflection mechanisms.
If you need too add hardcore dynamic nature to your software, you should be familliar with these documents:
Runtime Programming Guide: Introduction
Runtime Reference