Consider the following code:
enum CarError : Error { case noGas case tooSlow case tooFast(amount:Float) } class Car { private (set) var speed : Float = 0.0 init(amount:Float) throws { guard amount > 0 else { throw CarError.tooSlow } speed = amount } func moreGas(amount: Float) throws { guard amount > 0 else { throw CarError.tooFast(amount: amount) } speed += amount } func lessGas(amount : Float) throws { guard amount > 0 else { throw CarError.tooFast(amount: amount) } guard speed >= amount else { throw CarError.noGas } speed -= amount } }
If you preface a call to something that can throw an error with try?, and it does throw an error, the result will be nil:
let v = try? Car(amount: -50) // nil
The return type of any call that you try? will be an optional.
If you call a method with try!, and it throws an error, your program will simply crash.
This has the same effect as using try? to receive an optional and then using the force-unwrap operator ! on that optional:
let v = try! Car(amount: 50) // this call will exit or crash if we put in an invalid amount
The try? and try! statements do not need to be in a do-catch block.
If you do put them in do-catch block, any errors won't be caught by the catch block.
They'll still just either evaluate to nil or cause a crash.