Todayâs article will be about handling errors in Swift.
Because letâs be honest, that makes a fun post title for the season âď¸âď¸.
Objective-C and the NSError of its ways
Remember Objective-C? Back then1, the main and official way for a method to tell that something went wrong was to take a NSError* by reference.
NSError* error;
BOOL ok = [string writeToFile:path
atomically:YES
encoding:NSUTF8StringEncoding
error:&error];
if (!ok) {
NSLog(@"An error happened: %@", error);
}
Man that was painful. To the point that many people were tempted to not even bother to check for errors and simply pass NULL there. Not very responsible and safe.
Do you want to build a throw, man?

With Swift 2.0, Apple decided to introduce a different way to handle errors: using throw 2.
The use of throw is actually quite simple:
- If you want to create a function that might fail, mark it with
throwsin its signature; - Inside the function itself you can use
throw someErrorif needed; - At call site, youâll have to explicitly use
tryin front of your calls to methods which can throw3; - To catch errors and handle them, use
do { ⌠} catch { ⌠}constructs.
This looks like this:
// Define a function that can throwâŚ
func someFunctionWhichCanFail(param: Int) throws -> String {
...
if (param > 0) {
return "somestring"
}
else {
throw NSError(domain: "MyDomain", code: 500, userInfo: nil)
}
}
// ⌠then call it
do {
let result: String = try someFunctionWhichCanFail(-2)
print("success! \(result)")
}
catch {
print("Oops: \(error)")
}
The failure never bothered me anyway

You can see that someFunctionWhichCanFail returns a plain String, which is the type returned when everything was ok. It makes it easy to call the function ânormallyâ, first thinking (in the do { ⌠} block) about the happy path, to handle the case where nothing wrong happens.
The only reminder that those methods can fail is the try keyword that the compiler enforces you to add in front of that call, otherwise itâs like a non-throwing function call. And then, you only write the code to handle errors in a separate place (inside the catch)
Note that you can write more than one line (and try-call more than one throwing function) in that do block. If everything is successful, it will execute them as expected, but as soon as one of them fails it will jump out of the do block into the catch statement instead. Thatâs very handy as well for long runs of code with multiple potential points of failure, as you can handle them all in a single error path at the end.
NSError is a bit of a fixer-upper

Ok, but with this example we still have to handle errors using NSError, which is a pain. Comparing domains and error codes with == and make a list of domain and code constants, just to know which error we got and handle it properly⌠ouch.
But we can fix this fixer-upper⌠up with a little bit of love! What if we used what we learned in my Enums as Constants article and use enums to represent errors instead?
Well, Good news, everyone!â˘, thatâs exactly what Apple intended in this new error handling model!
In fact, when a function throws, it can throw any object which conforms to ErrorType. NSError is one of those types, but you can make your own, and itâs even recommended!
The best fit for an ErrorType type is an enum, which can even have associated values if needs be. For example:
enum KristoffError : ErrorType {
case ClumsyWayHeWalks
case GrumpyWayHeTalks
case PearShapedSquareShapedWeirdnessOfHisFeet
case NotWashedSince(days: Int)
}
Then you can now use throw KristoffError.NotWashedSince(days: 3) in a function to throws this kind of error, then use catch KristoffError.NotWashedSince(let days) at call site to catch such errors:
func loveKristoff() throws -> Void {
guard daysSinceLastShower == 0 else {
throw KristoffError.NotWashedSince(days: daysSinceLastShower)
}
...
}
do {
try loveKristoff()
}
catch KristoffError.NotWashedSince(let days) {
print("Ewww, he hasn't had a shower since \(days) days!")
}
catch {
// Any other kind of error, whatever it is
print("I prefer we stay friends")
}
Thatâs way easier to catch specific errors than having to compare domains and error codes!
That also makes better errors with clear names as constants and associated values. No more obscure userInfo, you have a clear list of associated values right there in the enum case of the error â like days in the above example â which are only valid for that specific type (wouldnât make sense to have that days associated value for the ClumsyWayHeWalks error).
I canât hold it back anymore

When you call a throw-ing function, the error it throws can be caught in the calling function using a doâŚcatch. But if it isnât, then it propagates to the upper level:
func doFail() throws -> Void { throw ⌠}
func test() {
do {
try doTheActualCall()
} catch {
print("Oops")
}
}
func doTheActualCall() throws {
try doFail()
}
Here when doFail is called, the potential error is not caught by doTheActualCall (there is no doâŚcatch capturing it), so it propagates up to the calling test() function. Because it doesnât catch all errors, doTheActualCall must also be marked as throws: even if it doesnât throw errors by itself, it can still propagate some. It canât keep the error to itself, it has to⌠let it go to the upper level.
On the other end, test() catches all errors internally so even if it calls a throwing function (try doTheActualCall()), all errors thrown by that function are caught in the doâŚcatch block. The test() function itself doesnât throw, so callers donât need to know about this internal behavior.
Conceal, donât feel, donât let them know

You may have wondered by now how to know which kind of error each method throws. Indeed, functions are marked with throws but what ErrorType can this function actually throw? Can it throw KristoffErrors, JSONErrors, other? Which ones do I need to catch?
Well thatâs a problem. Currently, due to some ABI and resilience concerns4, this is not possible. The only way to know is using the documentation of your code.
But thatâs also a good thing. For example, imagine you use two libraries, MyLibA containing a function funcA that throws errors of type MyLibAError, and MyLibB with a function funcB that throws errors of type MyLibBError.
Then you want to create your own library MyLibC, a wrapper around those two libraries, with a function funcC() calling both MyLibA.funcA() and MyLibB.funcB(). So the resulting function funcC might throw either errors of type MyLibAError or MyLibBError. And if you add another level of abstraction, it gets worse, with more and more error types being able to be thrown. If we had to list them all, and the call site would need to catch them all, that would make a quite verbose signature and catch code.
Donât let them in, donât let them see

For that reason, but also to prevent your internal errors from bleeding across your library boundaries and to limit the number of error types that must be handled by your users, I suggest that you keep your error types scoped to each level of abstraction.
In the example above, instead of making funcC directly propagate both MyLibAErrors and MyLibBErrors, you should instead throw MyLibCErrors. I suggest this for two reasons, both related to abstraction:
- Your users shouldnât have to know which internal library youâre using. If some day in the future you decide to switch your implementation to use
SomeOtherPopularLibAinstead ofMyLibA, which will obviously not throw exactly the same errors, the caller of your ownMyLibCframework shouldnât need to know or care. Thatâs what abstraction is all about. - The caller shouldnât have to handle all the errors. Surely you can catch some of those errors and consider them internal: not all errors thrown by
MyLibAmake sense to be exposed publicly to your users, for example aFrameworkConfigurationErrorerror mentioning that you misused theMyLibAframework and forgot to call itssetup()method or whatever should not make its way to the user, as the user canât do much about it. That kind of error is your fault, not theirs.
So instead, your funcC should probably catch all MyLibAErrors and MyLibBErrors, wrap them / re-interpret them and expose them as MyLibCErrors instead. That way, the users of your framework donât have to know what youâre using under the hood. You can switch your internal implementation and libs used at any time, and you expose to the user only the errors they might care for.
We finish each others sandwiches5

There is a lot more to tell about throw and the Swift 2.0 error model. I could talk about try? and try!, about the rethrows keyword for high-order functions.
I wonât have time to talk about every subject about error handling there, that would have made that post way too long; but other interesting blog posts might help you finish your exploration in the world of Swift error handling, including (but not limited to) those:
- Throw that donât throw and ReâŚthrows? by Rob Napier
- Error Handling by Little Bites of Cocoa
- What we learned from rewriting our robotic control software in Swift, by Brad Larson
- ⌠(Donât hesitate to share more links in the comments section!)
Let me finish this article by wishing you all happy holidays âď¸âď¸ and see you soon for the next post!

-
For more info about how the old way to handle errors in Objective-C work, see this great article by NSHipster. But todayâs article is about Swift and the new way, so letâs not lose too much time about that old beast. ↩
-
Despite its name,
throwis not about throwing exceptions like in Java or C++ or even ObjC. But the way to use it is so similar that Apple decided to keep the same wording so that people used to exceptions find it natural. ↩ -
This is enforced by the compiler, the aim being to let you realize that this function can go wrong and you have to handle the potential error ↩
-
Swift 2.0 doesnât support typed throws, but there is a discussion about adding that feature in the swift-evolution Mailing List where Chris Lattner explains why this was not possible in Swift 2 and why we need the resilience model of Swift 3.0 to be able to make that feature consistent. ↩
-
Ok, promise, that was my last shameful Frozen reference. ↩