From "objc.h":
typedef struct objc_class *Class;
but in "runtime.h":
struct objc_class {
Class isa;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
What exactly is Class
?
typedef struct objc_class *Class;
^ That is a forward declaration for an objc_class
pointer. It gives it the nice friendly name Class
.
Now lets take a look at the objc_class
struct: (Removing Objective-C 2.0 checks to shorten it up)
struct objc_class {
Class isa;
};
//This is really saying
struct objc_class {
struct objc_class *isa;
};
So now we have a struct that points to its own type. But why you ask?
Taken from Inside the Objective-C Runtime, Part 2
The Class pointed to by the Class' isa (the Class' Class) contains the Class' class methods in its objc_method_list. Got that? The terminology used in the runtime is that while an object's isa points to its Class, a Class's isa points to the object's "meta Class".
So what about a meta Class' isa pointer? Well, that points to the root class of the hierarchy (NSObject in most cases). (In the Foundation framework each meta class of a subclass of NSObject "isa" instance of NSObject.) And yes, by the way, NSObject's meta Class' isa points back to the same struct -- it's a circular reference so no Class' isa is ever NULL.
So according to that description when you create a class inheriting from NSObject
you have an isa
that points to its class type which points to its meta class which points to its root class (NSObject
) which contains a circular reference to itself. This explains the reason why it requires two steps to determine if an object is an instance or a class.
Lets say you create the following class:
@interface MyClass : NSObject
@end
@implementation MyClass
@end
If you were able* to traverse the isa pointer you would get the following:
*You can not since the isa
is protected. See Cocoa with Love post below for creating your own implementation.
Class c = myClassInstance->isa; //This would be the MyClass
c = c->isa; //This would be MyClass' meta class
c = c->isa; //This would be NSObjects meta class
c = c->isa; //This going forward would still be the NSObjects meta class
...
Once c == c->isa
you will know you are at the root object. Remember that Objective-C is a proper superset of C, which does not natively have object-oriented constructs such as inheritance. This along with other implementation details, such as pointers to super classes which make up the full class hierarchy, allows Objective-C to provide object-oriented features. For more information on classes and meta-classes see the post on Cocoa with Love: What is a meta-class in Objective-C?