id
Take another look at the initializer’s declaration; its return type is id (pronounced “eye-dee”). This type is defined as “a pointer to any object.” (id is a lot like void * in C.) init methods are always declared to return id.
Why not make the return type BNRItem *? After all, that is the type of object that is returned from this method. A problem will arise, however, if BNRItem is ever subclassed. The subclass would inherit all of the methods from BNRItem, including this initializer and its return type. An instance of the subclass could then be sent this initializer message, but what would be returned? Not a BNRItem, but an instance of the subclass. You might think, “No problem. Override the initializer in the subclass to change the return type.” But in Objective-C, you cannot have two methods with the same selector and different return types (or arguments). By specifying that an initialization method returns “any object,” we never have to worry what happens with a subclass.
isa
As programmers, we always know the type of the object that is returned from an initializer. (How do we know this? It is an instance of the class we sent alloc to.) The object itself also knows its type – thanks to its isa pointer.
Every object has an instance variable called isa. When an instance is created by sending alloc to a class, that class sets the isa instance variable of the returned object to point back at the class that created it (Figure 2.13). We call it the isa pointer because an object “is a” instance of that class.
The isa pointer is where Objective-C gets much of its power. At runtime, when a message is sent to an object, that object goes to the class named in its isa pointer and says, “I was sent this message. Run the code for the matching method.” This is different than most compiled languages, where the method to be executed is determined at compile time.
super
Often when you are overriding a method, you want to keep what the method of the superclass is doing and have your subclass add something new on top of it. To make this easier, there is a compiler directive in Objective-C called super:
- (void)someMethod {
[self doMoreStuff];
[super someMethod]; }
How does super work? Usually when you send a message to an object, the search for a method of that name starts in the object’s class. If there is no such method, the search continues in the superclass of the object. The search will continue up the inheritance hierarchy until a suitable method is found. (If it gets to the top of the hierarchy and no method is found, an exception is thrown.)
When you send a message to super, you are sending a message to self, but the search for the method skips the object’s class and starts at the superclass.
In simple applications like RandomPossessions, we only use a handful of classes. However, as applications grow larger and more complex, the number of classes grows. At some point, you will run into a situation where you have two classes that could easily be named the same thing. This is bad news. If two classes have the same name, it is impossible for your program to figure out which one it should use. This is known as a namespace collision.
Other languages solve this problem by declaring classes inside a namespace. You can think of a namespace as a group, to which classes belong. To use a class in these languages, you have to specify both the class name and the namespace.
Objective-C has no notion of namespaces. Instead, we prefix class names with two or three letters to keep them distinct. For example, in this exercise, the class was named BNRItem instead of Item.
Stylish Objective-C programmers always prefix their model and view classes. The prefix is typically related to the name of the application you are developing or the library it belongs to. For example, if I were writing an application named “MovieViewer,” I would prefix all classes with MV. Classes that you will use across multiple projects typically bear a prefix that is related to your name (JC), your company’s name (BNR), or a portable library (a library for dealing with maps might use MAP).
Controller objects, on the other hand, are typically only used in a single application and do not need a prefix. This isn’t a rule – you can prefix your controller objects if you like, and you definitely should if they will be used in other applications.
Notice that Apple’s classes have prefixes, too. Apple’s classes are organized into frameworks (which we’ll talk about in Chapter 4), and each framework has its own prefix. For instance, the UILabel class belongs to the UIKit framework. The classes NSArray and NSString belong to the Foundation framework. (The NS stands for NeXTSTEP, the platform for which these classes were originally designed.)