TL ; DR:
When a method can't do what it was asked, it throws an error. The code that called it catches the error with do, try and catch.
struct WalletError: Error {
let message: String
}
func spend(_ amount: Int) throws {
if amount > money {
throw WalletError(message: "not enough money")
}
money -= amount
}
do {
try wallet.spend(80)
} catch let error as WalletError {
print("error: \(error.message)")
} catch {
print("error: \(error)")
}
Full lesson:
Some requests can't be done. A wallet with 50 can't spend 80.
The method could return a special value, like -1. But the caller may forget to check it. Then the program goes on with a wrong number.
An error that the method throws is better. The program can't miss it.
Throwing an error
- Any type that adopts the
Errorprotocol can be thrown.WalletErroris a struct with a message. - A method that can throw says
throwsin its header, before the return type. throw WalletError(message: "not enough money")stops the method at once.- The lines after it don't run. So the wallet keeps its money.
Catching it
- Call the method inside a
doblock, withtryin front of the call. - When the call throws, the rest of the
doblock is skipped. catch let error as WalletErrorruns for aWalletError.- Swift wants every error caught. A last plain
catchtakes any other kind. - Then the program goes on below the last
catch.
Swift checks this when it compiles. A call that can throw needs try, and its errors must be caught.
Your task
A Wallet starts with 50. Its spend method takes money out and returns what is left.
- In
spend, throw aWalletErrorwhenamountis more thanmoney. Its message is"not enough money". - In the loop, call
spendwithtryinside adoblock. Print what was spent and what is left. - Catch the
WalletError. Printerror:and its message. Then add a plaincatchfor any other error.
The loop tries to spend 20, then 40, then 30.
Expected output:
spent 20, 30 left
error: not enough money
spent 30, 0 leftFree plan: 30 tutor messages. Premium is unlimited.
