Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

People also ask

What is self in Objective C?

self is a special variable in Objective-C, inside an instance method this variable refers to the receiver(object) of the message that invoked the method, while in a class method self will indicate which class is calling.

What is super in Objective C?

Super is self , but when used in a message expression, it means "look for an implementation starting with the superclass's method table."

What is init in Objective C?

init() Implemented by subclasses to initialize a new object (the receiver) immediately after memory for it has been allocated.


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.


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.


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.


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.


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.


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.