Dealing with Failure in Objective-C initializers

Most introductory texts on Objective-C cover the two step process to allocate and initialize a new object but do not say much about what you should do if the initialization fails. I suspect the reason for this is that most of the time initializers don’t do much that could go wrong. One situation where an initializer can fail is when it depends on a resource which may not always be available or which could be in error. For example, data which must be retrieved from a file or a remote network resource.

Initializing Objects

Before looking at how to handle failure conditions in the initializer it is worth reviewing some of the key points about an Objective-C initializer. A simple but fairly typical initializer for an Objectve-C class may look something like this:

- (id)initWithValue:(NSUInteger)someValue {

  self = [super init];
  if (nil != self) {

    // Set some ivars
    someIvar = someValue;
  }

  return self;
}

The key points to note are as follows:

Dealing with Failure

In this simple example of an Objective-C initializer handling failure is pretty simple. The only way the initializer can really fail is if the initializer of the superclass fails. In that case there is nothing to do but return nil to the caller (making sure not to access any of the ivars). Testing for a failure at this point is good practise even if you think the initializer can never fail since you never know how the superclass may be modified in the future.

So what happens when our initializer is a bit more complicated and needs to access some external resources to properly initialize the object:

- (id)initWithFile:(NSString *)filePath {

  self = [super init];
  if (nil != self) {
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
      // More code to read, validate and use file contents to
      // init the object
    } else {
      [self release];
      return nil;
    }
  }

  return self;
}

In this case we have an initializer that takes a single parameter which should be the path to a file used to initialize the object. After first initializing the superclass and checking for failure as before the class checks that the file actually exists. If the file does not exist the object cannot be initialized so we need to clean up and return nil to the caller.

However in this case we have already successfully initialized the superclass so we have a partially initialized object. We do not want to return this object to the caller since it is not fully initialized but if we just return nil we will create a memory leak. The solution is to send the release message to the superclass and let it clean up the resources allocated by the superclass.

In practise this type of initializer would be more complicated with many ways for failure. For example, we may start reading the file and only then find it is invalid. However the basic approach to failure is always the same. Any resources allocated in the initializer need to be released then the release message needs to be sent to the superclass. Finally we should return nil to the caller.

Never miss a post!

iOS Size Classes Cheat Sheet

Subscribe and get my free iOS Size Classes Cheat Sheet

Success! Now check your email to confirm your subscription and download your free guide to iOS Size Classes.

There was an error submitting your subscription. Please try again.

Unsubscribe at any time.
No time to watch WWDC videos?

Sign up to get my iOS posts direct to your inbox and I will send you a free PDF of my iOS Size Classes Cheat Sheet.

OK! Check your inbox (or spam folder) for an email to confirm your details and download your free guide to iOS Size Classes.

There was an error submitting your subscription. Please try again.

Unsubscribe at any time.
Archives Categories