macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Understanding Exceptions and Handlers in Cocoa
Pages: 1, 2, 3, 4, 5, 6, 7

Handling Other Cocoa Objects

Finally, the basic handler can trap other Cocoa objects besides an NSException. Simply use the @throw keyword to send the Cocoa object to the handler. Then use the @catch keyword to trap that object.

To demonstrate, modify the divideLong:by: method as shown in Listing 8. The method stores the division results into the NSNumber local, loc_quot. Then it uses the @throw keyword to send the result to the handler. Notice that the return type for the method is changed to a void. Compare this method to those shown in Listing 4 and Listing 6.

Listing 8. Using the @throw directive
- (void)divideLong:(NSNumber *)aDividend 
             by:(NSNumber *)aDivisor
{
    NSException     *loc_err;
    NSNumber        *loc_quot;
    long         loc_long;
    
    // validity check
    if ((aDividend == nil) || (aDivisor == nil))
    {
        // create and send an exception signal
        loc_err = [NSException exceptionWithName:NSInternalInconsistencyException
                reason:@"Nil input arguments are sent" 
                userInfo:nil];
        [loc_err raise];
    }
    else
    {
        loc_long = [aDivisor longValue];
        if (loc_long == 0)
        {
            // create and send an exception signal
            loc_err = [NSException exceptionWithName:NSInvalidArgumentException
                    reason:@"Division by zero attempted" 
                    userInfo:nil];
            [loc_err raise];
        }
        else
        {
            // perform the division
            loc_long = [aDividend longValue] / loc_long;
            
            // return the results using @throw
            loc_quot = [NSNumber numberWithLong:loc_long];
            @throw loc_quot;
        }
    }
}

Now, modify the exception handler as shown in Listing 9. The second @catch block has an NSNumber as its argument. It retrieves the value of the argument and displays it using the NSLog() function. Also, if you run the modified code, you will see the same set of messages in the Xcode console window.

Listing 9. Trapping a thrown Cocoa object
NSNumber *tst_dividend, *tst_divisor, *tst_quotient;
NSString *tst_name;

// prepare the trap
@try
{
    // initialize the following locals
    tst_dividend = [NSNumber numberWithLong:8];
    tst_divisor = [NSNumber numberWithLong:2];
    
    // attempt a division operation
    tst_quotient = [self divideLong:tst_dividend 
                    by:tst_divisor];
    
    // display the results
    NSLog (@"The answer is: %@", tst_quotient);
}
@catch (NSException *theErr)
{
    tst_name = [theErr name];
    if ([tst_name isEqualToString:NSInvalidArgumentException])
        NSLog (@"The answer is: INFINITY");
    else 
    {
        if ([tst_name isEqualToString:NSInternalInconsistencyException])
            NSLog (@"The answer is: UNDEFINED");
        else
            [theErr raise];
    }
}
@catch (NSNumber *theNum)
{
    // display the number results
    NSLog (@"The answer is: %@", theNum);
}
@finally
{
    //...
    // the housekeeping domain
    //...
}

Using the @throw keyword to return results has its own drawbacks.

  • It can make the code hard to debug and maintain. After all, the @throw keyword works in the same way as a goto statement.
  • Throwing an exception uses a lot of resources. Unwanted use of exceptions can give a software product a large memory footprint. It may also cause the product to perform slower.

When Handlers Are Nested

Sometimes, an exception handler is placed within another. This placement, called nesting, can happen either by consequence or by design. Learning how control flows inside nested handlers can help in debugging a faulty handler or in tracing an error signal.

Types of Nesting Structures

Exception handlers can be nested in three ways.

  • One handler is nested in another within the same method.
  • Both handlers are in different methods, which are in the same class. Then the handler in the first method calls the second method, which has the other handler.
  • Both handlers are in different methods, and the methods are in different classes. Then the method in the first class calls the method in the second class.

Listing 10 is an example of the first nesting structure. Here, demoMethod has two exception handlers. The outer @try block of the first handler contains the @try…@catch…@finally block of the second handler. This type of nesting often happens by design.

Notice that the two @catch blocks use different names for their NSException variable. This allows the handlers know which NSException to trap at that time. In the example shown, the inner handler traps only NSExceptions with the ID Inner Error, while the outer handler traps those with the ID Outer Error.

Listing 10. Handlers nested in the same method
- (void)demoMethod
{
    // ...
    // code before the handler
    // ...
    // start of the outer handler
    @try
    {
        // ...
        // code that could generate an outer exception
        // ...
        
        // start of the inner handler
        @try
        {
            // ...
            // code that could generate an inner exception
            // ...
        }
        @catch (NSException *theErr2)
        {
            // identify the exception
            if ([[theErr2 name] isEqualToString:@"Inner Error"])
                // ...
                // code to handle the inner exception
                // ...
            else
                [theErr2 raise];
        }
        @finally
        {
            // ...
            // finish the inner handler
            // ...
        }
    }
    @catch (NSException * theErr1)
    {
        // identify the exception
        if ([[theErr1 name] isEqualToString:@"Outer Error"])
            // ...
            // code to handle the outer exception
            // ...
            else
                [theErr1 raise];
    }
    @finally
    {
        // ...
        // finish the outer handler
        // ...
    }
}

Pages: 1, 2, 3, 4, 5, 6, 7

Next Pagearrow