1.8 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.
1.8.1 Object Error Handling
When an error occurs, the runtime sets in
motion the following sequence of events:
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.
The -error: method prepares information about the
receiver and passes it to the runtime C function
objc_verror(
).
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.
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_handler f)
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.
1.8.2 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:
One stack frame is popped from the runtime call stack.
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.
1.8.2.1 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.
 |
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.
1.8.2.2 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.
1 NS_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.
|