Initializers in Objective-C
As I mentioned in a previous post, I was on the Object Oriented Programming episode of the Mac Developer Roundtable. At one point, the discussion turned to the apparent self = [super init]
myth and how assigning to self
was not needed and should not be done. Here’s a transcript of my response (with a lot of embarrassing “you knows” removed). My actual response can be heard at 54:51 in the podcast:
Yeah, I mean I don’t want to talk about this too much because it really has nothing to do with object oriented programming. But the fact of the matter is
init
returns a value. And Apple’s documentation says you should assignself
to the return value. It’s the rule of the language. It kinda sucks; I wish they didn’t do it, and it’s rarely needed, but that’s how it is. And it’s really not a lot of work to call, to do that, just say “self = [super init]
” And I don’t really see any reason not to do it, and I don’t see any reason to recommend people not do to it because it’s the right way.
That’s all I said on the topic mainly because I thought it was off-topic, and others covered the technical details. However, I think it’s an interesting point, so I thought I’d take a moment to elaborate on my response.
For those late to the game, the controversy surrounds writing initializers in subclasses. Here’s a simple example that follows Apple’s guidelines:
- (id)init {
self = [super init];
if (self == nil)
return nil;
// Perform initialization
return self;
}
There’s a couple of weird things going on – weird, if you’re coming from another language, that is. First, you assign self
to the return value of the superclass’s initializer. Second, you check to see if that value is nil
, and return nil
yourself. The controversy surrounds assigning self
.
I’m on the side of following Apple’s guidelines, as my response in MDR indicated. I don’t think the only reason to assign self
is because the documentation says we should, but it is a major reason. Apple’s official documentation, while not perfect, is very good. Having worked on many other platforms before, I am constantly impressed with the quality and amount of the API documentation and guides that they publish.
But let’s be clear, Apple’s documentation is not gospel. It is written by humans, after all. There are plenty of cases where it’s lacking or even wrong, and I don’t hesitate to point this out.
That being said, when I read Apple’s documentation, I start from a position of trust. They’re certainly not trying to deceive us. Until I see some really good evidence to the contrary, I follow Apple’s documentation. If I encounter a discrepancy, depending on the situation and evidence, I file a bug report. This isn’t one of those cases.
Let’s look at what the documentation has to say on this specific issue. As part of the Introduction to the Objective-C 2.0 Programming Language document, there’s a whole section on implementing an initializer, along with an example implementation (which is equivalent to the example I gave above). In that section of the document, under the “Constraints and Conventions” subsection, one of the bullet points notes:
You should assign
self
to the value returned by the designated initializer.This is because the superclass’s initializer could return a different object than the original receiver.
Not only is it telling us what we should be doing, but it also tells us why. And the wording on the “why” is really the key part here. It says “could return a different object” (emphasis added) not “will.” This is an important difference. It means that if you don’t assign self
, you could be okay. It all depends on the what the superclass’s initializer does.
And this is where the controversy comes in. The argument goes that, in practice, no class you’d ever want to subclass from ever returns anything other than self
. Thus, assigning to self
is redundant and pointless and does not need to be done.
However, the superclass could return a different instance. No amount of empirical testing can refute this. Even if it’s rare that Apple’s classes currently do this, it cannot be proven that Apple won’t start doing this more in future versions of the OS. Nor can you control what third-party code does.
Case in point: the designated initializer for NSManagedObject
, a class introduced in Mac OS X 10.4, requires setting self
. Yes, I’m aware that you generally should not override this initializer in subclasses, and you should use awakeFromInsert:
or awakeFromFetch:
instead. But that doesn’t mean there is never a good reason to override this initializer, though I’ve never had to do it myself.
To me, this is about defensive coding and making your code future proof. By following this simple convention, I’m guaranteeing my code won’t break if some object’s initializer does return a different object. It’ll just work, and I won’t have to waste my time debugging it.
It’s also really easy to follow this convention. If you use some sort of macro, you never have to think about it. Xcode has a built-in text macro system, where you type “init<Control-.>
”, and you’ll get a template for an initializer. I prefer Completion Dictionary from Objective Development. It’s similar to Xcode’s macros, but it’s easier to customize and a bit more feature-rich. Whatever you choose, macros make following this convention a brainless task so you can think about more important things.
If you want to read more on this topic, in addition to Apple’s fine docs, Mike Ash wrote up a post that goes into more depth. He squashes a few myths that often come up about initializers and supports Apple’s claim that the superclass could return an object other than self
.
I still have yet to hear a convincing argument on why I should not assign self
. Until I do, I’ll be following Apple’s documentation, and I recommend that others do, too.
Update 6-Apr-2009: Added blurb about Xcode’s text macros.