In Swift, an error must be an object of a type that adopts the Error
protocol, which has just two requirements: a String _domain
property and an Int _code
property. The purpose of those properties is to help errors cross the bridge between Swift and Objective-C; in real life, you will be unaware of them (and in
fact you won’t even see them listed in the Swift header). The object will be one of the following:
Error
protocol, it is ready to be used as an error object; the protocol requirements are magically fulfilled for you, behind the scenes. Typically, this type will be an enum
, which will communicate its message by means of its cases: different cases will distinguish different kinds of possible failure, perhaps with raw values or associated types to carry further information.NSError
is Cocoa’s class for communicating the nature of a problem; Swift extends NSError
to adopt Error
and bridges them to one another. If your call to a Cocoa method generates a failure, Cocoa will send you an NSError
instance typed as an Error
.There are two stages of the error mechanism to consider - throwing an error, and catching an error:
To throw an error, use the keyword throw
followed by an error object. That’s all it takes! The current block of code is immediately aborted, and the error mechanism takes over. However, to ensure that the throw
command is used coherently, Swift imposes a rule that you can say throw only in a context where
the error will be caught.
The primary context for throwing and catching an error is the do...catch
construct. This consists of a do block and one or more catch blocks. It is legal to
throw in the do block; an accompanying catch block can then be fed any errors thrown from within the do block. The do...catch
construct’s schema looks like
do { statements // a throw can happen here } catch errortype { statements } catch { statements }
A single do
block can be accompanied by multiple catch
blocks. Catch blocks are like the cases of a switch
statement, and will usually have the same logic: first, you might have specialized catch blocks, each of which is designed to handle some limited set of possible errors; finally, you might have a general
catch block that acts as the default, mopping up any errors that were not caught by any of the specialized catch blocks.