ref – http://www.techotopia.com/index.php/Understanding_Error_Handling_in_Swift_2
In Swift, errors are represented by values of types that conform to the Error protocol. This empty protocol indicates that a type can be used for error handling.
Representing and Throwing Errors
In Swift, errors are represented by values of types that conform to the Error protocol. This empty protocol indicates that a type can be used for error handling.
1 2 3 4 5 |
enum FileTransferError: Error { case noConnection case lowBandwidth case fileNotFound } |
Handling Errors
When an error is thrown, some surrounding piece of code must be responsible for handling the error—for example, by correcting the problem, trying an alternative approach, or informing the user of the failure.
There are four ways to handle errors in Swift:
– You can propagate the error from a function to the code that calls that function
– handle the error using a do-catch statement
– handle the error as an optional value
– or assert that the error will not occur.
Propagate the error from a function to the code that calls that function
A throwing function propagates errors that are thrown inside of it to the scope from which it’s called.
hence, say our function fileTransfer throws an error.
We are call a throwing function with try phrase inside a do/try, where the catch code catches any errors thrown from the do function.
1 2 3 |
func fileTransfer(index num: Int) throws -> Void { // throw FileTransferError.noConnection } |
1 2 3 4 5 6 |
do { try fileTransfer(index: 0) } catch FileTransferError.noConnection { print("CAUGHT ----- NO CONNECTION!------") } |
Only throwing functions can propagate errors. Any errors thrown inside a nonthrowing function must be handled inside the function.
example:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
func nonThrowing(_ num: Int) { do { if (num < 0) { throw VendingMachineError.outOfStock } } catch VendingMachineError.outOfStock { print("threw VendingMachineError.outOfStock error!") } catch { print(".... default catch") } } // func |
by default, in order to run the throw catch mechanism in order to handle the error, we use do-catch statement.
Full SOURCE CODE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
// notice it derives from Error protocol enum FileTransferError: Error { case noConnection case lowBandwidth case fileNotFound } func fileTransfer(index num: Int) throws -> Void { print("------ fileTransfer function ---------") if(num == 0) { print("fileTransfer - THROW {NO CONNECTION} Error ") throw FileTransferError.noConnection } else if (num == 1) { print("fileTransfer - LOW BANDWIDTH!") throw FileTransferError.lowBandwidth } else { print("fileTransfer - FILE NOT FOUND!") throw FileTransferError.fileNotFound } } func func1() { print("clean THIS up! :D") } func func2() { print("clean THAT up! :D") } do { // the deferred functions are fun RIGHT AFTER a error is thrown // and RIGHT BEFORE it is caught defer { func1() func2() } try fileTransfer(index: 0) } catch FileTransferError.noConnection { print("CAUGHT ----- NO CONNECTION!------") } catch FileTransferError.lowBandwidth { print("CAUGHT ----- LOW BANDWIDTH :(") } catch FileTransferError.fileNotFound { print("CAUGHT ----- FILE NOT FOUND") } print("DONE!") |
OUTPUT:
—— fileTransfer function ———
fileTransfer – THROW NO CONNECTION!
clean THIS up! 😀
clean THAT up! 😀
CAUGHT —– NO CONNECTION!——
DONE!
Notice how our file transfer function runs first. Then right before it throws, it will call the defer functions.
After the defer functions are done executing, the exception is thrown and consequently, caught.