Chapter 2 id and initializers


Is this a typo?

Here’s the body of text

…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? [color=#FF0000]Not a BNRItem, but an instance of the subclass.[/color] 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…

Hillegass, Aaron; Conway, Joe (2012-03-14). iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides) (Kindle Locations 1784-1796). Pearson Education (US). Kindle Edition.

This is the issue: “Not a BNRItem, but an instance of the subclass.”

Shouldn’t that read “Not an instance of the subclass, but an instance of BNRItem.” The init method declared in BNRItem would return a pointer, (BNRItem *), and not a pointer to an object of its subclass (BNRItemSubclass *). The phrase “Not a BNRItem, but an instance of the subclass.” in the text contradicts this.

I know that using - (id) takes away all the problems but it is important for me to understand what the compiler is doing underneath the hood. For the moment, I’m inclined to think this is a minor typo but for a very literal minded person like me it’s confusing.


Nope, it’s correct.

The method’s return type will be “BNRItem *” but the actual object returned will be “BNRItemSubclass *”.

So, what this looks like is a method declared like so:

  • (BNRItem *)init;

And when inherited by BNRItemSubclass, the method is still

  • (BNRItem *)init;

But actually sending init in the following case does not return a BNRItem, but a BNRItemSubclass:

BNRItemSubclass *i = [[BNRItemSubclass alloc] init];

Which makes this really misleading - because if you read over the header file, you’d say “This is supposed to return a BNRItem, but I get a BNRItemSubclass!”