Error Handling in Swift 2.0
Swift 2.0 has a new way of error handling. It uses a do-try-catch syntax, which is the replacement for NSError . In this post we will discuss how to use this new syntax.
Defining an error
Before an error can be thrown or catched, it must be defined. You can define an error in Swift by an enum that implements the new ErrorType protocol:
enum MyErrorType : ErrorType { case SomeErrorCause case AnotherErrorCause }
Throwing an error
For a function to be able to throw an error, it must announce this in the function head by the keyword throws :
func testFunction() throws { }
Now this function can throw an error by using the keyword throw and the mention of the concrete error type:
func testFunction() throws { throw MyErrorType.SomeErrorCause }
Catching an error
If you just try to call this function, there will be a compiler error. Because the function announces that it is capable to throw an error, you will need to catch the potential error:
do { try testFunction() } catch { print("there was an error...") }
By the way: Because the do-try-catch syntax is similar to the do-while syntax, the latter is renamed to repeat-until.
Furthermore, in a do-try-catch block you have the possibility to catch several errors:
do { try testFunction() } catch MyErrorType.SomeErrorCause { print("there was an MyErrorType.SomeErrorCause-error...") } catch MyErrorType.AnotherErrorCause { print("there was an MyErrorType.AnotherErrorCause-error...") } catch { print("there was another error...") }
However, similar to switch, a do-try-catch block must be exhaustive. That means that all possible errors must be catched. Since the error throwing function does not announce what kind of errors it can throw, this means that all known errors must be catched. In practice this means that there need to be always a pure catch case.
Cleaning Up
If a function throws an error, then it will return immediately. But because sometimes things needs to be done before a functions returns, there is the new keyword defer. For example, this clean-up could be closing a file. With defer you can define a block of code that is always executed when a functions returns, no matter whether the function returns normally or due to an error.
You can define your defer block anywhere in your function. Furthermore, it is also possible to define more than one defer block. If you do so, all of these blocks will be executed in reverse order.
Take a look at an example:
func testFunction() throws { defer { print("clean-up") } throw MyErrorType.SomeErrorCause }
For more details, take a look at another blog post about this topic.
Error handling interoperability between Objective-C and Swift
Objectice-C is now 100% compatible to Swift’s new error handling. If you use NSError in the right way, the functions’s head is automatically translated to the correct Swift syntax. Let’s look at an example:
#import "ObjectiveCTestClass.h" @implementation ObjectiveCTestClass - (BOOL) doSomethingRiskyWithAString:(NSString*) aString error:(NSError**)error { if (aString == nil) { NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary]; [errorDetail setValue:@"Failed" forKey:NSLocalizedDescriptionKey]; *error = [NSError errorWithDomain:@"aDomain" code:100 userInfo:errorDetail]; return NO; } return YES; } @end
We have a test class with a function that satisfies two requirements:
- The function has as last parameter a pointer of type NSError** .
- The function returns something – that means the return type is not nil .
Now if you declare the ObjectiveCTestClass.h in the BridgingHeader file, the function head is translated to
doSomethinhRiskyWithAString(aString: String!) throws -> Bool
That means, you can call the Objective-C function from Swift in the following way:
let objectiveCTestObject = ObjectiveCTestClass() do { try objectiveCTestObject.doSomethingRiskyWithAString(nil) } catch let error as NSError { print("Error: (error.domain)") }
Note how you can get access to the NSError pointer in the catch block.
The other way round, if you call a Swift function that throws an error from Objective-C, the function is translated to the NSError syntax.
[thrive_text_block color=”blue” headline=”Conclusion”]
Swift’s new error handling model is a very important new feature. It is more intuitiv than the old NSError way but also very powerful. Like always, the interoperability between Swift and Objective-C is very good. You should be able to adapt very quickly.
[/thrive_text_block]
References
- WWDC 2015 – What’s New in Swift?
- Official Apple Developer Blog – Swift 2.0
- Image: @ iunewind / Shutterstock.com