Handling exceptions in Objective-C: Try, Catch and Finally

You won’t find exceptions used as frequently in Objective-C as in other languages. However, try/catch/finally blocks can be useful to capture errors that may otherwise cause an app to fail.

In the example below, I allocate an array, however I don’t add any elements to the array. Inside the try block the attempt to access the first element will cause an exception to be thrown.

NSArray* arraytest = [[NSArray alloc] init];
 
@try 
{
  // Attempt access to an empty array
  NSLog(@"Object: %@", [arraytest objectAtIndex:0]);
 
}
@catch (NSException *exception) 
{
  // Print exception information
  NSLog( @"NSException caught" );
  NSLog( @"Name: %@", exception.name);
  NSLog( @"Reason: %@", exception.reason );
  return;
}
@finally 
{
  // Cleanup, in both success and fail cases
  NSLog( @"In finally block");
 
  [arraytest release];
}

The output of the code is shown below:

iPhoneApp[4464:b903] NSException caught
iPhoneApp[4464:b903] Name: NSRangeException
iPhoneApp[4464:b903] Reason: *** -[NSArray objectAtIndex:]: index 0 beyond bounds for empty array
iPhoneApp[4508:b903] In finally block

The @finally clause is called regardless of the outcome of the code the in @try block. This is the perfect place to perform any relevant code cleanup.

Using exceptions can be helpful when working with files (for example NSFileHandleOperationException), when working with data from unknown sources, etc.

Catching a Specific Exception

Using NSException as shown in the @catch statement above, will result in all exceptions being caught. You can also look for a specific exception – the code below looks only for NSRangeException:

@try 
{
  // Attempt access to an empty array
  NSLog(@"Object: %@", [arraytest objectAtIndex:0]);
 
}
@catch (NSRangeException *exception) 
{
  // Print exception information
  NSLog( @"NSRangeException caught" );
  NSLog( @"Reason: %@", exception.reason );
  return;
}
@finally 
{
  // Cleanup, in both success and fail cases
  NSLog( @"In finally block");
 
  [arraytest release];
}
Throwing an Exception

You can also throw an exception in your own code. Although a bit contrived (as a means to get the point across), the method testException() shown below will throw an exception whenever it is called:

- (void)testException
{
  if (1 == 1) 
  {
    NSException *exception = [NSException exceptionWithName: @"Exception!"
                                                     reason: @"Something not so good occurred."
                                                   userInfo: nil];
    @throw exception;
  }
}

Further along in the code, when testException() is called, wrap the invocation in a try/catch/finally blocks in a manner similar to what was shown above:

@try 
{
  // Call the method...
  [self testException];
}
@catch (NSException *exception) 
{
  // Print exception information
  NSLog( @"NSException caught" );
  NSLog( @"Name: %@", exception.name);
  NSLog( @"Reason: %@", exception.reason );
  return;
}
@finally 
{
  NSLog( @"In finally block");
}

iPhoneApp[4660:b903] NSException caught
iPhoneApp[4660:b903] Name: Exception!
iPhoneApp[4660:b903] Reason: Something not so good occurred.
iPhoneApp[4660:b903] In finally block