If you’re an Objective-C developer you can get a lot done without understanding the C roots in Objective-C or the object model employed by Objective-C. In fact, trying to learn the object model can be intimidating and confusing because some peculiar complexities.
Even if it’s a little complex, it’s a worthy endeavor to learn the Objective-C object model because you may end up needing to interact with the Objective-C runtime someday, and understanding the object model will be very useful in that situation.
Grab a cup of tea or coffee and follow along with me while we explore the Objective-C object model.
Objects are instances of a class
Sure, this may sound obvious, but it’s worth taking a few seconds to really consider what it means when we say that an object is an instance of a class. Take the following code for example:
NSString *name =
[NSString stringWithFormat:@"%@", @"Peter"];
This is a rather contrived example but it’s important to demonstrate
some of the moving parts in the Objective-C runtime. When the code
above is executed we end up with a variable called name that is an
instance of the NSString class. Please consider the following:
-
Objects (instances of a class) are used to hold state.
-
An object’s state is held in its instance variables. For example, the
nameobject above owns some memory for storing the bytes that make up the string “Peter”. -
The
nameobject also contains a pointer back to its class (NSString) as part of its state. -
In Objective-C objects don’t contain any behavior, only state.
-
Classes contain behavior and do not contain any state. The behavior they hold is the methods that their instances can respond to.
-
Let’s repeat that once again for clarity. Objects are containers that store state (instance variables) and classes are containers that store behavior (methods).
To make this more concrete take a look at the following diagram:

The blue box represents the name variable (an instance of the
NSString class). Using the diagram above let’s look at what happens
if you send the length message to the name variable:
NSUInteger len = [name length];
-
The first thing that Objective-C does is ask the
namevariable which class it was instantiated from. Since all the methods are held in the class, that’s where it will start looking for thelengthmethod. -
Since the class of
nameobject isNSString, Objective-C goes to theNSStringclass and searches for thelengthmethod. -
If Objective-C finds the
lengthmethod in theNSStringclass it will stop searching and execute the method that it found. Otherwise it will continue searching the inheritance hierarchy for the method.
I should note that the process I’m describing has been simplified. I’m not considering other places that methods could be stored (e.g. Objective-C categories).
Classes are really objects too
Given that a class holds methods for its instances, you might be
wondering where class methods are stored. Let’s look at the code that
created the name variable again:
NSString *name =
[NSString stringWithFormat:@"%@", @"Peter"];
In the code above, the stringWithFormat: message was sent to the
NSString class. Can classes receive messages, and if so where are
those methods kept? In this case, the Objective-C syntax is covering
something up, it’s hiding the fact that NSString is also an object.
If NSString is an object, that means that it must have been
instantiated from a class that is holding its methods. This is true,
but before we dig into it let’s look at some more code:
@interface Person : NSObject {}
+ (void) aClassMethod;
- (void) anInstanceMethod;
@end
You’ve probably seen this many, many times. But what is really going on?
-
A new class is being declared, the
Personclass. -
This class will be used to hold methods for instances.
-
A second class is also being created behind the scenes. Unfortunately this additional class has the same name (
Person) but is referred to as thePersonmetaclass. -
The
Personmetaclass holds the class methods for thePersonclass.
This can be very confusing because the same name is being used over
and over again. Going back to our name variable, we can say the
following:
-
The
nameobject is an instance of theNSStringclass. -
NSStringis an object instantiated from theNSStringmetaclass. -
If you send the
lengthmessage to thenameobject, Objective-C will go look for that method in theNSStringclass. -
If you send the
stringWithFormat:message to theNSStringobject, Objective-C will go look for that method in theNSStringmetaclass.
Here’s another diagram:

This time the blue box represents the NSString object. Here’s the
creation of the name object again:
NSString *name =
[NSString stringWithFormat:@"%@", @"Peter"];
When the stringWithFormat: message is sent to the NSString object
Objective-C will:
-
Ask the
NSStringobject for it’s class, which is theNSStringmetaclass. -
It will then start searching the
NSStringmetaclass for thestringWithFormat:method. If it doesn’t find the method there it will continue up the inheritance hierarchy.
Naturally, since the NSString class inherits from the NSObject
class, the NSString metaclass inherits from the NSObject
metaclass.
Wacky NSObject inheritance
If you’ve made it this far you can rest assured that you know enough
about the Objective-C object model to know a lot more about what’s
going on in your code at run time. There’s just one more thing that
you may want to know: Why does it look like the NSObject metaclass
inherits from the NSObject class? Because it does.
Consider the following:
-
The
NSObjectclass contains methods for its instantiated objects. -
The
NSObjectmetaclass contains methods for theNSObjectclass (i.e.NSObjectclass methods). -
The
NSObjectmetaclass inherits from the (non-meta)NSObjectclass. -
Therefore, any instance methods defined for
NSObjectwill also be in the search path as class methods for any Objective-C class.
It’s a bit wacky, but if you look at the diagram above it should start to make sense.