Mac OS X Reference Library Apple Developer
Search

Nesting Exception Handlers

Exception handlers can be nested so that an exception raised in an inner domain can be treated by the local exception handler and any number of encompassing exception handlers. This design allows an exception to be handled by code that, although it is further from the code actually generating the exceptionö, might have more knowledge about the conditions leading to the exception.

You can nest exception handlers using both the @try...@catch...@finally directives and the NS_DURING...NS_HANDLER...NS_ENDHANDLER macros. There are some subtle differences in these mechanisms between the flow of program control from inner exception handler to outer exception handler, so the following sections discuss them separately.

Important: The compiler directives discussed below were introduced in Mac OS X v10.3. An application that uses these directives for exception handling cannot run on earlier versions of the operating system.

Nested Exception Handlers With Compiler Directives

To understand how nested exception handlers defined with the compiler directives are invoked, consider the code fragment in Listing 1.

Listing 1  Throwing and rethrowing an exception

@try {
    // ...
    if (someError) {
        NSException *theException = [NSException exceptionWithName:MyAppException reason:@"Some error just occurred!" userInfo:nil];
        @throw theException;
    }
}
@catch (NSException *exception) {
    if ([[exception name] isEqualToString:MyAppException]) {
        NSRunAlertPanel(@"Error Panel", @"%@", @"OK", nil, nil,
                localException);
    }
    @throw; // rethrow the exception
}
@finally {
    [self cleanUp];
}

In this code the exception (exception) is thrown again at the end of the local handler, allowing an encompassing exception handler to take some additional action. Figure 1 illustrates the flow of program control between nested exception handlers created with the @catch directive.

Figure 1  Control flow with nested exception handlers‚Äîusing directives

Control flow with nested exception handlers—using directives

An exception raised within Method 3's domain causes execution to jump to its local exception handler. In a typical application, this exception handler queries the exception object to determine the nature of the exception. The local handler may handle exception types that it recognizes and then may rethrow the exception object to pass notification of the exception to the handler nested above it—that is, the handler in Method 2. However, before the next outer exception handler is invoked, the code in the @finally block associated with the local exception handler is executed. (This has implications for memory management, as discussed in “Exception Handling and Memory Management .”)

An exception that is rethrown appears to the next higher handler just as if the initial exception had been raised within its own exception handling domain. Method 2's exception handler again may handle the exception and may rethrow the exception to Method 1's exception handler; Method 1’s handler does not receive the rethrown exception until Method 2’s @finally block completes its task. Finally, Method 1’s handler rethrows the exception. Because there is no exception handling domain above Method 1, the exception passes to the uncaught exception handler (see “Uncaught Exceptions”).

Nested Exception Handlers With Exception Macros

You program should use the exception-handling macros if it must be compatible with versions of the operating system prior to Mac OS X v10.3. If you are using the exception-handling macros, the code equivalent to that in Listing 1 would look something like Listing 2.

Listing 2  Raising and re-raising an exception

NS_DURING
    ...
    if (someError) {
        NSException *theException = [NSException exceptionWithName:MyAppException reason:@"Some error just occurred!" userInfo:nil];
        [theException raise];
    }
    [self cleanUp];
NS_HANDLER
    if ([[localException name] isEqualToString:MyAppException]) {
        NSRunAlertPanel(@"Error Panel", @"%@", @"OK", nil, nil,
                localException);
    }
    [self cleanUp];
    [localException raise]; /* Re-raise the exception. */
NS_ENDHANDLER

In this code the exception (exception or localException) is raised again at the end of the local handler, allowing an encompassing exception handler to take some additional action. Figure 2 illustrates the use of nested exception handlers, and is discussed in the text that follows.

Figure 2  Control flow with nested exception handlers‚Äîusing macros

Control flow with nested exception handlers—using macros

An exception raised within Method 3’s domain causes execution to jump to its local exception handler. In a typical application, this exception handler checks the object localException to determine the nature of the exception. For exception types that it recognizes, the local handler responds and then may send raise to localException to pass notification of the exception to the handler above, the handler in Method 2. (An exception that is re-raised appears to the next higher handler just as if the initial exception had been raised within its own exception handling domain.) Method 2’s exception handler does the same and then re-raises the exception to Method 1’s handler. Finally, Method 1’s handler re-raises the exception. Since there is no exception handling domain above Method 1, the exception is transferred to the uncaught exception handler (see “Uncaught Exceptions”).




Last updated: 2010-02-24

Did this document help you? Yes It's good, but... Not helpful...