Learn Objective-C on the Mac - Mark Dalrymple [119]
The following example shows creating the same exception as before, but now within a@try block. We catch it in the @catch block and output an error message, then move on to the @finally section, which is executed no matter what happens. In this simple case, we don’t need the @finally section and could just omit it, but it can be useful in situations where some resource is initialized in the @try block and needs to be freed up.
This example handles the exception in the same method where it was raised, but that’s actually pretty uncommon. More likely, no local exception handler is found, so the system traverses the call stack looking for an exception handler, first in the current method’s caller, then that method’s caller, and so on. This search continues down the call stack until an exception handler is found. If none is found, a special-case scenario can be configured to handle the uncaught exception. By default, a Cocoa app that encounters an uncaught exception will print some info about the exception to the console log, and then try to continue running as usual.
The Limited Role of Exceptions in Cocoa
In Cocoa, exceptions are used to make a method break out of its normal operating flow in case of a serious problem that should not occur while the program is running. In general, if your code causes an exception to be raised, you’ve got a bug. With few exceptions, a properly written Cocoa program should be able to run forever without a single exception ever being raised.
If you have a background in Java, Ruby, Python, or C++, this may seem a little restrictive. In many other environments, exceptions are used a little more freely, such as a file-reading method raising an exception to tell the caller that it’s read to the end of the file (which, if you think about it, is not an exceptional state at all, because every file has an end). In Python, one common idiom for iterating through an array is to increment an index, try to read the indexed value from the array, and catch the resulting exception when you read past the end. In Cocoa, however, this sort of thing is frowned upon, and exceptions are normally used only for reporting unexpected results that are probably caused by a bug in the program.
Because of the rather limited role of exceptions in Cocoa, you don’t often see a lot of exception-handling code inside Cocoa apps. Unlike Java, Objective-C doesn’t require (or even allow) its methods to specify what kinds of exceptions they may raise, and in theory you don’t really have to handle them at all. By default, each Cocoa app you create will have a sort of top-level exception handler that simply outputs some information about the exception to the system log, and then lets the app continue on its way as best it can. Unfortunately, this isn’t much of a strategy, because whatever your app was doing at the time of the exception was most likely happening in response to the last user action (clicking a button, pressing a key, and the like), and whatever else that action was supposed to be doing after that is just skipped right over, potentially leaving your application in an undefined or inconsistent state!
Some applications install a special top-level exception handler of their own to deal with these situations. Xcode, for instance, occasionally hits an exception (yes, even Xcode has bugs!), at which point it typically gives you to the opportunity to quit the app, recognizing the possibility that something is mucked up.
Create a Test-bed
Let’s build a small application that demonstrates some of the kinds of exceptions that Cocoa programmers are likely to encounter. In Xcode, create a new Cocoa