Optional Return vs throws: Pick One

Swift 2 provides a number of ways to indicate a problem in a method that returns a value, but the two most common are optional return values and throwing errors. Which you choose comes down to your requirements for a particular function, which I will discuss below. But if you take nothing else away from this post, take this: Don’t use both!

That is not to say you can’t use both approaches in your app, just don’t use them both in a single function.

Optional Returns

Pros: Simple to write, simple to handle
Cons: Uninformative

The most common method for indicating failure in a function that returns a value is to make that value optional and return nil when a problem occurs that prevents the successful completion of the function. This has been available since Swift 1.0 and the language has a lot of syntactical features to allow you to efficiently detect and handle nil responses.

Optional returns should be your first choice when all you care about is whether or not a value was returned from a function, not why the function may have failed.

Example:

Throwing Functions

Pros: Informative errors allow robust recovery options, non-optional return values
Cons: More verbose syntax to handle errors (if you don’t just ignore them with try?)

Swift 2 introduced a robust error handling mechanism to Swift. Functions marked with throws can throw errors which calling objects must explicitly handle or ignore. Having a well-defined set of errors allows calling objects to implement an intelligent recovery plan in the event of a failure, such as correcting erroneous input and trying again. The down-side is that writing error handling code gets verbose, with the do-catch blocks.

Example:

Combining Optional Returns and Errors

Don’t! If you don’t want to bother with errors, then your method should just return an optional value. If you do go to the effort of adding errors, let them communicate problems and guarantee a non-nil return value from your function. If the calling object doesn’t want to handle the errors, it can simply invoke your function with try? and treat the return value as optional. If the calling function does handle the errors, allow it to forgo the extra steps of handling optional return values.