views:

505

answers:

4

I've just been reading up on how to properly fail in an init method and the docs seem to disagree with each other. One recommends throwing an exception while the others recommend cleaning up and returning nil. What's the current best practice here?

A: 

The method I've always used is cleaning up and returning nil. The three methods you mention in your question title may cause segfaults higher up in the call hierarchy, whereas returning nil will not. I believe that the Apple docs themselves say to return nil on failure. Where are you finding discrepancies?

Marc W
Simply returning nil will leak memory, since the call to alloc will have created an object with a retain count of one.
Marc Charbonneau
The memory leak is what I want to avoid.
Kevin
Links to docs:Error Detection During Initialization - http://tr.im/mlyAImplementing an Initializer - http://tr.im/mlyXYou'll notice that under the sample code in the second link they recommend throwing an exception instead. I'm pretty sure that's not the current best practice.
Kevin
I believe the exception referred to means throwing an exception if the input is nil (illegal parameter). I always validate parameters to my methods using NSParameterAssert(...), even in init methods. This is standard practice because it represents a programming error, not a runtime one.
sbooth
+6  A: 

I believe that the generally accepted practice is to return nil on failure. But you do want to release self to avoid a leak:

-(id)init
{
  if (self = [super init]) {
    ...
    if (thingsWentWrong) {
      [self release];
      return nil;
    }
    ...
  }
  return self;
}
n8gray
Thanks for the feedback guys. This is what I was doing and had thought to be the proper approach but the references to the other two methods in the docs had me thinking there might be some special cases to be aware of.
Kevin
+5  A: 

Cocoa's philosophy on exceptions is that they should only be thrown in situations that are programmer errors, like passing an illegal argument to a method. If something else goes wrong, the method should just return NO or nil, and hopefully report the details via an NSError** "out" parameter.

This includes -init methods. If the error situation is something that could legitimately occur in the finished product, then the method should release self (to avoid a leak) and return nil.

Jens Alfke
+6  A: 

The correct solutions (exceptions and/or [self release]; return nil;) having been covered, I'll address the incorrect solutions.

Don't send dealloc directly. That's release's job. (And if your code is ever running under GC, dealloc is inapplicable, and I could only speculate on what problems calling it would cause.)

Double-don't use super to send it directly. That would skip over your own dealloc implementation.

Peter Hosey