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

Objective CNullInit

Objective C Problem Overview


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?

Objective C Solutions


Solution 1 - Objective C

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 - Objective C

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 - Objective C

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 - Objective C

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.

Solution 5 - Objective C

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.

Solution 6 - Objective C

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.

Solution 7 - Objective C

A common mistake is to write

self = [[super alloc] init];

which returns an instance of the superclass, which is NOT what you want in a subclass constructor/init. You get back an object that does not respond to the subclass methods, which can be confusing, and generate confusing errors about not reponding to methods or identifiers not found, etc.

self = [super init]; 

is needed if the super class has members (variables or other objects) to initialize first before setting up the subclasses' members. Otherwise the objc runtime initializes them all to 0 or to nil. (unlike ANSI C, which often allocates chunks of memory without clearing them at all)

And yes, base class initialization can fail because of out-of-memory errors, missing components, resource acquisition failures, etc. so a check for nil is wise, and takes less than a few milliseconds.

Solution 8 - Objective C

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...

Solution 9 - Objective C

In OS X, it's not as likely for -[NSObject init] to fail due to memory reasons. The same cannot be said for iOS.

Also, it's good practice for writing when subclassing a class that might return nil for whatever reason.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJasarienView Question on Stackoverflow
Solution 1 - Objective CiKenndacView Answer on Stackoverflow
Solution 2 - Objective CbbumView Answer on Stackoverflow
Solution 3 - Objective CGinoView Answer on Stackoverflow
Solution 4 - Objective Cuser123444555621View Answer on Stackoverflow
Solution 5 - Objective CJohn RudyView Answer on Stackoverflow
Solution 6 - Objective Candyvn22View Answer on Stackoverflow
Solution 7 - Objective CChris ReidView Answer on Stackoverflow
Solution 8 - Objective CDanielView Answer on Stackoverflow
Solution 9 - Objective CMaddTheSaneView Answer on Stackoverflow