objective-c

What to do if [super init] returns nil?


Take the following code as an example

- (id)init {
    self = [super init];
    if (self) {
        // code
    }
    return self;
}

I do not want nil to propagate up the calling hierarchy. My initial idea is to throw an exception in case self is nil, make a restore point and abort execution.

Better ideas?


Solution

  • NSObject's implementation of [super init] will never return nil. The base implementation just returns self.

    In general, the only reason that an initializer returns nil is if a nonfatal error occurred. For example, you might have called -initWithContentsOfURL:error: and passed an invalid URL. By convention, methods that may fail in this way have an error: parameter, which contains information about the failure. Most initializers do not have the possibility of a recoverable error, so like NSObject, they will never return nil.

    Fatal errors typically throw an exception or abort the program. So checking for nil is no help with them. Your best bet to handle fatal errors is NSSetUncaughtExceptionHandler, although you should be aware that saving data is risky in the case of a fatal error, as the unsaved data may be corrupted. Don't overwrite good data in that case.

    Why does objective-c code always check for nil in initializers, even when super will never return nil? Convention, mostly. Arguably, by always checking for nil, it becomes easier for a superclass to add a failure condition in the future without requiring subclasses to be changed, but really it's just a convention.

    Finally, the initalizer is not the right place to check for failure in a superclass initializer. If recoverable errors are a possibility, the caller should check for the error.

    Example:

    NSError *error;
    FooClass *myFoo = [[FooClass alloc] initWithContentsOfURL:blah error:&error]
    if (myFoo == nil) {
      // ...
    } else {
      // ...
    }
    

    Checking for nil whenever you initialize an object is overkill. This only needs to be done when there is an error: argument, or the method has a documented recoverable error.