views:

2784

answers:

8

Hey guys,

I have a general question about writing init methods in Objective-C.

I see it everywhere (Apple's code, books, open source code, etc.) that an init method should check if self = [super init] is not nil before continuing with initialisation.

The default Apple template for an init method is:

- (id) init
{
    self = [super init];

    if (self != nil)
    {
        // your code here
    }

    return self;
}

Why?

I mean when is init ever going to return nil? If I called init on NSObject and got nil back, then something must be really screwed, right? And in that case, you might as well not even write a program...

Is it really that common that a class' init method may return nil? If so, in what case, and why?

A: 

This is to check that the intialazation worked, the if statement returns true if the init method did not return nil, so its a way to check creation of the object worked correctly. Few reasons i can think of that init might fail maybe its an overriden init method that the super class does not know of or something of the sort, I wouldnt think it is that common though. But if it does happen, its better nothing to happen that a crash i supose so its always checked...

Daniel
Memory allocation is done in alloc, though, not init.
Jasarien
it is, but htey are called together, what happens if alloc f ails?
Daniel
im just making a guess tho, i might be wrong
Daniel
I imagine if alloc fails, then init will be sent to nil rather than an instance of whatever class you're calling init on. In that case, nothing will happen, and no code will be executed to even test whether or not [super init] returned nil.
Jasarien
yea im probably wrong in that statement
Daniel
Memory allocation is not always done in +alloc. Consider the case of class clusters; an NSString doesn't know which specific subclass to use until the initializer is invoked.
bbum
+8  A: 

For example:

[[NSData alloc] initWithContentsOfFile:@"this/path/doesn't/exist/"];
[[NSImage alloc] initWithContentsOfFile:@"unsupportedFormat.sjt"];
[NSImage imageNamed:@"AnImageThatIsntInTheImageCache"];

... and so on. (Note: NSData might throw an exception if the file doesn't exist). There are quite a few areas where returning nil is the expected behaviour when a problem occurs, and because of this it's standard practice to check for nil pretty much all the time, for consistency's sake.

iKenndac
Yes, but this isn't INSIDE the respective class' init method.NSData inherits from NSObject. Does NSData check if [super init] returns nil?That's what I'm asking here. Sorry if I wasn't clear...
Jasarien
If you were to subclass those classes, there would be a pretty real chance that [super init] will return nil. Not all classes are direct subclasses of NSObject. There's never any guarantee that it will not return nil. It's just a defensive coding practice that's generally encouraged.
Chuck
@Jasarien: It CAN be done inside your `super`'s init method, which you are calling. Sure, NSObject probably won't fail to init, but if you're subclassing MyDataAndImageClass, then it could very well fail in its `init`.
jbrennan
I agree with both Chuck and jbrennan. Plus, when I make a new class it takes 5 seconds to write `if (self = [super init])`, but a considerable amount more to find out if my superclass can return nil. Which it can, of course — when you run out of memory.
iKenndac
but in my subclass I wouldn't be calling -init, I'd be calling initWithImage: or initWithContentsOfFile: in which case, I would expect a nil. But when subclassing an NSObject, should nil ever come around?
Jasarien
Yes — if you run out of memory. It's rare, but it can happen. Plus, for the sake of a line of code, why are you so hell bent on not doing The Best Thing? Defensive code is good code.
iKenndac
I doubt NSObject init can return nil in any case, ever. If you're out of memory, the alloc will fail, but if it succeeds, I doubt init could fail - NSObject doesn't even have any instance variables except Class. In GNUStep, its implemented as just "return self", and disassembling on the Mac looks the same. All this is, of course, irrelevent - just follow the standard idiom and you wont have to worry about whether it can or can't.
Peter N Lewis
I'm not hell bent on not following best practices. I would, however, like to know why they are best practises in the first place. Its like being told to jump off a tower. You don't just go ahead and do it unless you know why. Is there a big, soft pillow to land on at the bottom, with a massive cash reward? If I knew that I'd jump. If not, I wouldn't. I don't want to just blindly follow a practise without know why I am following it...
Jasarien
That's also not to say that my code doesn't follow this. I do the check in all my subclasses, I just want to know why I'm doing it ;)
Jasarien
@Jasarien: The reason is that there's generally no guarantee any arbitrary init method will not return nil at some point, so it's a good practice to be into. Personally, I think it's kind of paranoid, but that is the reason.
Chuck
If alloc returns nil, init is sent to nil, which will always result in nil, this ending up with self being nil.
Toon Van Acker
@Chuck, what I don't get about all of this is that, when you construct an instance of a class, unless you KNOW that it might be null for some reason, you don't check if it's null. So your code will blow up happily anyway. So do these bulletproof constructors make sense in the context of code that doesn't check if the object is null anyway? Seems like a silly convention, and conciseness does count.
Yar
+2  A: 

Wil Shipley posted an article related to this a while back.

self = [stupid init];

Read through the comments as well, some good stuff.

Ryan Townshend
Very interesting trivia to piggyback this comment: with -Wall ` works fine.
Justin Searls
+12  A: 

You could ask Wil Shipley or Mike Ash or Matt Gallagher. Either way, it's something of a debated topic. But usually it's good to stick with Apple's idioms... it's their Frameworks, after all.

jbrennan
It seems Wil was making a case more for not blindly reassigning self during init, knowing that [super init] may not return the receiver.
Jasarien
Wil has changed his thoughts since that post was originally made.
bbum
+1 for those awesome links.
Frank Shearar
+1 bravo, great links. Man I have to get back to writing code and stop reading all this stuff. But first let me note that NONE of the authors is suggesting not using the `if`. But @Jasarien already said that, pretty much...
Yar
+2  A: 

Typically, if your class derives directly from NSObject, you won't need to. However, it's a good habit to get into, as if your class derives from other classes, their initializers may return nil, and if so, your initializer can then capture that and behave correctly.

And yes, for the record, I follow the best practice and write it on all my classes, even those deriving directly from NSObject.

John Rudy
A: 

You're right, you could often just write [super init], but that wouldn't work for a subclass of just anything. People prefer to just memorize one standard line of code and use it all the time, even when it's only sometimes necessary, and thus we get the standard if (self = [super init]), which takes both the possibility of nil being returned and the possibility of an object other than self being returned into account.

andyvn22
+8  A: 

This particular idiom is standard because it works in all cases.

While uncommon, there will be cases where...

[super init];

... returns a different instance, thus requiring the assignment to self.

And there will be cases where it will return nil, thus requiring the nil check so that your code doesn't try to initialize an instance variable slot that no longer exists.

The bottom line is that it is the documented correct pattern to use and, if you aren't using it, you are doing it wrong.

bbum
A: 

This is kind of a summary of the comments above.

Let's say the superclass returns nil. What's gonna happen?

If you don't follow the conventions

Your code is gonna crash in the middle of your init method. (unless init does nothing of significance)

If you follow the conventions, not knowing that the superclass might return nil (most people end up here)

Your code is probalby gonna crash at some point later, because your instance is nil, where you expected something different. Or your program is gonna behave unexpectedly without crashing. Oh dear! Do you want this? I don't know...

If you follow the conventions, willingly allowing your subclass to return nil

Your code documentation(!) should clearly state: "returns ... or nil", and the rest of your code needs to be prepared for handling this. Now it makes sense.

Pumbaa80