Exceptions

An exception is an event that occurs during the execution of a program that disrupts the normal flow of instructions.

An Error protocol represents an error value that can be thrown. Swift’s enumerations are well suited to represent simple errors.

enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(coinsNeeded: Int)
    case outOfStock
}

The throw statement allows you to throw exception. It is convenient to throw exception in guard statement instead if statement.

throw VendingMachineError.insufficientFunds(coinsNeeded: 5)

Error handling in Swift doesn’t involve unwinding the call stack, a process that can be computationally expensive. As such, the performance characteristics of a throw statement are comparable to those of a return statement.

The throws keyword indicates that fuction or method can throw an error. A function marked with throws is called a throwing function.

A throwing function propagates errors that are thrown inside of it to the scope from which it’s called.

func myFunc1(arg: String) {
    // This method is not throwing any errors
}

func myFunc1(arg: String) throws {
    // The throws keyword makes that this method cán throw an error
}

func myFunc2(arg: String) throws -> String{
    // The throws keyword makes that this method cán throw an error
    
    return ""
}

A throwing function must be called in try statement or its variations try?, try!.

try myFunc1()
let str = try? myFunc2("hello")
// if myFunc2 fails, str will have nil value

let str = try! myFunc2("hello")
// if myFunc2 fails, application will be crushed with
// Fatal error: ‘try!’ expression unexpectedly raised an error ...

A do-catch statement allows handle exceptions raised in try statement.

/* general form of a do-catch statement
    do {
        try expression
        statements
    } catch pattern 1 {
        statements
    } catch pattern 2 where condition {
        statements
    } catch pattern 3, pattern 4 where condition {
        statements
    } catch {
        statements
    }
*/

    var vendingMachine = VendingMachine()
    vendingMachine.coinsDeposited = 8
    do {
        try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
        print("Success! Yum.")
    } catch VendingMachineError.invalidSelection {
        print("Invalid Selection.")
    } catch VendingMachineError.outOfStock {
        print("Out of Stock.")
    } catch VendingMachineError.insufficientFunds(let coinsNeeded) {
        print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
    } catch {
        print("Unexpected error: \(error).")
    }
    // Prints "Insufficient funds. Please insert an additional 2 coins."