In Objective-C why should I check if self = [super init] is not nil?

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?


Solution 1:

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.

Solution 2:

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.

Solution 3:

I think, in most classes, if the return value from [super init] is nil and you check it, as recommended by standard practices, and then return prematurely if nil, basically your app is still not going to work correctly. If you think about it, even though that if (self != nil) check is there, for proper operation of your class, 99.99% of the time you actually do need self to be non-nil. Now, suppose, for whatever reason, [super init] did return nil, basically your check against nil is basically passing the buck up to the caller of your class, where it would likely fail anyways, since it will naturally assume that the call was successful.

Basically, what I'm getting at is that 99.99% of the time, the if (self != nil) does not buy you anything in terms of greater robustness, since you're just passing the buck up to your invoker. To really be able to handle this robustly, you would actually need to put in checks in your entire calling hierarchy. And even then, the only thing it would buy you is that your app would fail a little more cleanly/robustly. But it would still fail.

If a library class arbitrarily decided to return nil as a result of a [super init], you're pretty much f***ed anyways, and that's more of an indication that the writer of the library class made a mistake of implementation.

I think this is more of a legacy coding suggestion, when apps ran in much more limited memory.

But for C level code, I would still typically check the return value of malloc() against a NULL pointer. Whereas, for Objective-C, until I find evidence to the contrary, I think I'll generally skip the if (self != nil) checks. Why the discrepancy ?

Because, at the C and malloc levels, in some cases you actually can partially recover. Whereas I think in Objective-C, in 99.99% of cases, if [super init] does return nil, you're basically f***ed, even if you try to handle it. You might as well just let the app crash and deal with the aftermath.

Solution 4:

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.