I’m new to Objective-C, and I see that there are different conventions used about error handling. There are exceptions, but also there are situations where functions are just supposed to return nil in case of something going wrong.
So, how do I decide when use which, and how to handle exceptions and unexpected return values? What are the best practices and red flags?
I won’t be definitive about which to use, but here’s some info about each of the options:
Exceptions
Exceptions in Obj-C are not really meant to be used to control program flow. From the documentation on exception handling:
For this reason I wouldn’t recommend using exceptions
@try/@catchjust to test whether a method worked correctly.You also have several options for handling exceptions, in addition to setting a higher-level uncaught exception handler.
Errors
Errors are typically used in three ways:
Delegate methods
An object can simply pass an NSError to its delegate in a designated error-handling callback:
The delegate is then free to take any appropriate action, including perhaps displaying a message to the user. This pattern is commonly used in asynchronous delegate-based APIs.
Out parameters
These are most commonly used in conjunction with a boolean return value: if the return value is
NO, then the NSError object can be examined for more information about the error.Where one possible usage pattern would be:
(Some people also prefer to store the boolean result in a variable before checking it, such as
BOOL success = [myObject perform...];.) Due to the linear nature of this pattern, it’s best used for synchronous tasks.Block-based completion handlers
A fairly recent pattern since the introduction of blocks, yet a quite useful one:
Used like this:
This varies a lot: sometimes you won’t see the boolean parameter, just the error; sometimes the handler block has no arguments passed to it and you just check a state property of the object (for example, this is how AVAssetExportSession works). This pattern is also great for asynchronous tasks, when you want a block-based approach.
Handling errors
Cocoa on Mac OS X has a quite thorough error-handling path. There is also NSAlert’s convenience method
+ (NSAlert *)alertWithError:(NSError *)error;. On iOS, the NSError class still exists, but there aren’t the same convenience methods to handle errors. You may have to do a lot of it yourself.Read the Error Handling Programming Guide for more information.
Returning nil
This is often used in conjunction with NSError out parameters; for example, NSData’s method
If reading the file fails, this method returns
nil, and further information is stored in an error.One reason this is a particularly convenient pattern is because of nil messaging, which can be done safely with no effect in Obj-C. I won’t go into detail here on why this is useful, but you can read more about it elsewhere on the interwebs. (Just make sure to find an up-to-date article; it used to be that methods returning floating-point values wouldn’t necessarily return 0 when sent to nil, but now they do, as described in the documentation.)