Runtime Errors

Runtime errors include program errors like unhandled method calls or messages sent to released objects, and hardware errors like division by zero. The Object root class provides simple error-handling capability; the Cocoa framework implements exception raising and handling.

Object Error Handling

When an error occurs, the runtime sets in motion the following sequence of events:

  1. The runtime calls the -error : method on the object whose method generated the error. You can override this method to customize error handling for a particular class.

  2. The -error: method prepares information about the receiver and passes it to the runtime C function objc_verror( ) .

  3. The objc_verror( ) function calls the runtime error handler function if there is one; otherwise it writes an error message to stderr. You can provide a handler function to customize error handling for all classes.

  4. If the error handler exists (because you’ve provided one) and it returns YES, execution continues; otherwise the program calls the C function abort( ) and exits.

The GNU runtime provides a function to set your own error handler function:

objc_error_handler objc_set_error_handler(objc_error_handlerf)

Calling this function sets a new error handler and returns the previous one. The default error handler is a NULL pointer. The required signature of an error handler is declared (in objc-api.h) as:

typedef 
               BOOL (*objc_error_handler)
  (id receiver, 
   int errCode, 
   const 
               char* format, 
   va_list args);

Here are descriptions of the parameters your error handler will get:

receiver

The object in whose method the error occurred.

errCode

One of a set of integers declared in the header file objc-api.h along with objc_error_handler .

format

A printf-style C string, for printing an error message.

args

A variable-length list of values for the format string. You can print the error message using the format and argument list and the C function vprintf( ) .

Use the first two parameters to decide how to handle the error, and the second two to print a message.

Exceptions in Cocoa

The Cocoa framework contains an NSObject class that provides similar error-handling to the GNU Object. However, Cocoa also provides a more elaborate exception mechanism for handling errors.

An exception is a runtime event that diverts a program from its normal flow of control. In the extreme case, the program will exit immediately. More generally, control may jump across several stack frames, bypassing permanently the remaining code in nested method calls. (Cocoa uses the C setjmp( ) and longjmp( ) calls to implement this.) The Objective-C runtime or your code may generate (“raise”) exceptions to signal an event that must be handled in a special way.

Cocoa’s exception handling partitions your code into three types:

Try blocks

A block of code whose exceptions (if raised) will be sent to the immediately following handler section. Always precedes a handler. (The term “try” is borrowed from C++, even though Objective-C doesn’t use it as a keyword.)

Handlers

A block of code executed if an exception is raised. A handler always follows a try block.

Ordinary code

Any code that is not in a try block or handler.

These kinds of code play the following roles when an exception is raised:

  • If execution is in a try block, control jumps to the subsequent handler.

  • If execution is in ordinary code (or a handler), the following sequence occurs:

    1. One stack frame is popped from the runtime call stack.

    2. Control returns immediately to the routine that called the just-exited routine.

This process repeats from the first bullet point until either control is inside a handler or the entire call stack is popped.

The result is that a handler will handle exceptions raised directly in its preceding during block, and may handle those generated indirectly (through any level of routine calls), if there are no handlers closer to the source of the exception. If there are no explicit handlers in the current call chain, the uncaught exception handler will be called.

Keywords for handling exceptions

The Cocoa framework provides some definitions, variables, and functions to simplify exception creation, propagation, and handling:

NS_DURING

Starts a try block: a region of code that may generate exceptions. You don’t have to test the result of each operation to see if an exception occurred: if one does, control will jump to the handling section.

NS_HANDLER

Starts an exception handling section that corresponds to the preceding try block. In this section, the variable localException will exist and be set to the exception raised.

NS_ENDHANDLER

Ends the exception handling section.

NS_VOIDRETURN

Exits a method without returning a value. Use this macro when you need to exit a method from within a try block. Do not use the return keyword inside of a try block.

NS_VALUERETURN ( value )

The same as NS_VOIDRETURN, but used to return a value.

Note

If you leave the method using return, the exception mechanism will lose track of the call stack. If later code raises an exception, your program will probably crash.

localException

Defined in the handler with the value of the exception that was raised to get there.

NSUncaughtExceptionHandler

A C typedef for a function that takes an NSException* and returns void. The return or parameter type for the following two functions:

NSUncaughtExceptionHandler* NSGetUncaughtExceptionHandler( )
void NSSetUncaughtExceptionHandler (NSUncaughtExceptionHandler*)

Use these methods to retrieve or set the function the runtime calls for unhandled exceptions. The default function provided by the runtime writes an error message to stderr and exits the program.

A Cocoa exception handling example

The following example illustrates raising and handling an exception within the Cocoa framework. The example explicitly raises an exception in order to demonstrate how that’s done, but be aware that the Objective-C runtime can also implicitly raise exceptions.

 1NS_DURING
 2   NSException* ex = 
 3     [[NSException alloc]
 4      initWithName:@"ExceptionName"
 5            reason:@"description"
 6          userInfo:nil];
 7   [ex raise];
 8 NS_HANDLER
 9   if ([[localException name] 
10       isEqualToString:@"ExceptionName"])
11    // Handle exception.
12   else
13     [localException raise];
14 NS_ENDHANDLER

Line 1. Start the try block with the NS_DURING macro.

Line 2. Create an exception instance.

Line 4. Exceptions are distinguished—in code—by their names. Cocoa defines 22 names stored in global variables such as NSRangeException. You can use one of these or provide your own name.

Line 5. The reason can be any string. In contrast with the name, it’s meant to be read by people, so make it descriptive.

Line 6. The user info is an instance of NSDictionary —a class that provides a mapping between key-value pairs. You can use this to provide detailed information about the error.

Line 7. You raise an exception by calling its raise method.

Line 8. The NS_HANDLER macro ends the try block and starts the handler.

Line 9. Inside the handler, the variable localException is defined. Use its name to decide what to do about it.

Line 11. This part is up to you.

Line 13. If you can’t recover from the error, continue the exception by raising it again. This is optional.

Line 14. The NS_ENDHANDLER macro ends the handler section, and the exception-aware section as a whole.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.237.194