Previously we learn how to type cast in ObjC : Ojbective-C Type Casting
Almost
every app encounters errors. Some of these errors will be outside of your
control, such as running out of disk space or losing network connectivity. Some
of these errors will be recoverable, such as invalid user input. And, while all
developers strive for perfection, the occasional programmer error may also
occur.
In Objective-C, there are two types of errors that can
occur while a program is running. Unexpected errors are
"serious" programming errors that typically cause your program to
exit prematurely. These are called exceptions, since they represent an
exceptional condition in your program. On the other hand, expected
errors occur naturally in the course of a program's execution and can be used
to determine the success of an operation. These are referred to as errors.
Exceptions are used to inform the programmer about
something that went wrong, while errors are used to inform the user that
a requested action could not be completed.
For example, trying to access an array index that doesn't
exist is an exception (a programmer error), while failing to open a file is an
error (a user error). In the former case, something likely went very wrong in
the flow of your program and it should probably shut down soon after the
exception. In the latter, you would want to tell the user that the file
couldn't be opened and possibly ask to retry the action, but there is no reason
your program wouldn't be able to keep running after the error.
Exception Handling
The main benefit to Objective-C's exception handling
capabilities is the ability to separate the handling of errors from the detection
of errors. When a portion of code encounters an exception, it can
"throw" it to the nearest error handling block, which can
"catch" specific exceptions and handle them appropriately. The fact
that exceptions can be thrown from arbitrary locations eliminates the need to
constantly check for success or failure messages from each function involved in
a particular task.
The @try, @catch(), and @finally compiler directives are used to catch and handle
exceptions, and the @throw directive
is used to detect them. If you've worked with exceptions in C#, these exception
handling constructs should be familiar to you.
It's important to note that in Objective-C, exceptions are
relatively slow. As a result, their use should be limited to catching serious
programming errors-not for basic control flow.
In Objective-C programming,
exception handling is provided with NSException class available in Foundation framework.
The NSException Class
Exceptions are represented as instances of the NSException class or a subclass thereof. This is a convenient way to encapsulate all the necessary information associated with an exception.
The three properties that constitute an exception are described as follows:
- name - An instance of NSString that uniquely identifies the exception.
- reason - An instance of NSString containing a human-readable description of the exception.
- userInfo - An instance of NSDictionary that contains application-specific information related to the exception.
Generating Exceptions
Let's start by taking a look at the default
exception-handling behavior of a program. The objectAtIndex: method of NSArray
is defined to throw an NSRangeException (a subclass of NSException) when you
try to access an index that doesn't exist. So, if you request the 10th
item of an array that has only three elements, you'll have yourself an
exception to experiment with:
#import< Foundation/Foundation.h>
int main(int argc, const char * argv[]){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
NSArray *crew = [NSArray arrayWithObjects:
@"Dave",
@"Heywood",
@"Frank", nil];
// This will throw an exception.
NSLog(@"%@", [crew objectAtIndex:10]);
[pool init];
return 0;
}
When it encounters an uncaught exception occurred…
Uncaught exception NSRangeException, reason: Index 10 is out of range 3 (in 'objectAtIndex:')
Catching Exceptions
To handle an exception, any code that may result in
an exception should be placed in a @try block. Then, you can catch specific
exceptions using the @catch() directive. If you need to execute any
housekeeping code, you can optionally place it in a @finally block. The
following example shows all three of these exception-handling directives:
@try {
NSLog(@"%@", [crew objectAtIndex:10]);
}
@catch (NSException *exception) {
NSLog(@"Caught an exception");
// We'll just silently ignore the exception.
}
@finally {
NSLog(@"Cleaning up");
}
This should output the following in your Xcode console:
Caught an exception!
Name: NSRangeException
Reason: *** -[__NSArrayI objectAtIndex:]: index 10 beyond bounds [0 .. 2]
Cleaning up
When the program encounters the [crew objectAtIndex:10]
message, it throws an NSRangeException, which is caught in the @catch()
directive. Inside of the @catch() block is where the exception is actually
handled. In this case, we just display a descriptive error message, but in most
cases, you'll probably want to write some code to take care of the problem.
When an exception is encountered in the @try block, the program jumps to the corresponding @catch() block, which means any code after the exception occurred won't be executed. This poses a problem if the @try block needs some cleaning up (e.g., if it opened a file, that file needs to be closed). The @finally block solves this problem, since it is guaranteed to be executed regardless of whether an exception occurred. This makes it the perfect place to tie up any loose ends from the @try block.
Next, we will learn about : Objective-C Error Handling
Leave Comment