oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Inside the Objective-C Runtime, Part Two

by Ezra Epstein

Editor's note -- In his previous article, Ezra Epstein showed how to access the basic features of the Objective-C runtime. In this follow-up article, he digs a little deeper and looks at how the runtime is implemented. This digging results in a better understanding of Categories, and it also reveals details that may not be present in header (.h) files. The culmination of this brief foray is a look at RuntimeBrowser, a class-browsing tool like the JavaBrowser that the author has found quite useful and thinks you might too.

Digging Deeper Into Runtime

The Objective-C runtime is written in C. In fact, the original version of Objective-C was implemented as a C compiler pre-processor. To get "inside" the Objective-C runtime we use C functions to access C data structures. The central C struct is struct objc_class* (a.k.a., a Class).

To get the struct and function definitions we'll include the objc header files. They should already be on your system in: /usr/include/objc (or System/Developer/Headers/objc). You don't need Mac OS X, however. The source code and the headers for the runtime are available as part of the Darwin open source project: objc4-217.tar.gz. (If you haven't already you'll need to register to download the source, but registration is free.)

In the previous article, we got a class from a name (NSString*). But what if we want to list out all the classes loaded in the runtime? Fire up your editor of choice (I used ProjectBuilder and started with a "Tool" project) and make sure the header files from objc are in your include path (they should be by default).

#import <stdio.h>
#import <objc/objc-runtime.h>
#import <objc/hashtable.h>
void showIvars(Class klass) {  /* code is below */ }
void showMethodGroups(Class klass, char mType) { /* code is below */ }
int main (int argc, const char *argv[]) {
    NXHashTable * class_hash = objc_getClasses(); // NOT in a multi-threaded*** App.
    NXHashState state = NXInitHashState(class_hash);
    struct objc_class * klass;
    while (NXNextHashState(class_hash, &state, (void **)&klass)) {
        printf ("%s\n", klass->name);
        showMethodGroups(klass, '-'); // instance methods
        showMethodGroups(klass->isa, '+'); // class methods
    return 0;

Please note -- The runtime code changed somewhat since Mac OS X. It now uses locks to support multi-threaded access. The code above will work on the greatest number of deployed systems. For details on how to use the newer function, see the comment for objc_getClassList() in objc-runtime.h or see the code in AllClasses.m of the RuntimeBrowser.

Compile this and run it. Since showIvars() and showMethodGroups() are just stubs -- which we'll fill in later -- you'll get class names without other details. Which classes you see depends on which Frameworks (or other ObjC binaries) you've linked in. By default, using ProjectBuilder, you'll see all of the classes in the Foundation.framework. This includes hidden, undocumented classes and sub-classes of class clusters like NSString!

Take a look at objc/objc.h. Among other things, you'll see:

typedef struct objc_class *Class;

Yup, a Class is a pointer to struct objc_class as advertised. Once we've got a Class we access runtime information from this struct. While we're here let's look for a moment at the definition of type id (the universal Objective-C object pointer) also defined in objc/objc.h:

typedef struct objc_object {
    Class isa;
} *id;

An object of type id is a pointer to a struct that contains a single element: an isa pointer to its struct objc_class in the runtime. That's it.

Pages: 1, 2

Next Pagearrow