1. assert和precondition
//: Playground - noun: a place where people can play
import UIKit
// 下面的三个用于调试,在真机上不起作用
assert(1>0) // 必须满足括号里面的逻辑,不然停止
assert(1>0, "Error") // 必须满足括号里面的逻辑,不然停止并报错
assertionFailure("Error!") // 直接停止并报错
// 下面的三个和assert作用一模一样,在真机上也起作用
precondition(1>0)
precondition(1>0, "Error")
fatalError("Error")
2. throw,throws,系统自带的协议Error
import UIKit
// 自动贩卖机
class VendingMachine {
struct Item {
enum ItemType: String {
case Water
case Cola
case Juice
}
let type: ItemType
let price: Int
var count: Int
}
// 继承一个错误处理的类,名字叫Error
enum ItemError: Error {
case NoSuchItem
case NotEnoughMoney(Int)
case OutOfStock
case OtherError
}
private var items = ["Mineral Water" : Item(type: .Water, price:2, count:10),
"Coca Cola" : Item(type: .Cola, price: 3, count: 5),
"Orange Juice" : Item(type: .Juice, price: 5, count: 3)]
func vend(itemName: String, money: Int, count: Int) throws -> Int { // 如果有错误就抛出,没有就正常运行
guard let item = items[itemName] else {
throw ItemError.NoSuchItem // 程序结束,抛出异常
}
guard money >= item.price else {
throw ItemError.NotEnoughMoney(item.money) // 并携带一个返回值,是应付单价
}
guard item.count > 0 else {
throw ItemError.OutOfStock
}
guard count > 0 else {
throw ItemError.OtherError
}
dispenseItem(itemName: itemName)
return money - item.price * item.count
}
private func dispenseItem(itemName: String) {
items[itemName]?.count -= 1
print("Enjoy your \(itemName)")
}
}
3.try、do-catch、catch let ... as
对于一个这样的函数
func vend(itemName itemName: String, money: Int) throws -> Int{
guard let item = items[itemName] else{
throw VendingMachine.ItemError.NoSuchItem
}
guard money >= item.price else{
throw VendingMachine.ItemError.NotEnoughMoney(item.price)
}
guard item.count > 0 else{
throw VendingMachine.ItemError.OutOfStock
}
dispenseItem(itemName: itemName)
return money - item.price
}
自定义的错误如下
enum ItemError: Error, CustomStringConvertible{ //swift 3
case NoSuchItem
case NotEnoughMoney(Int)
case OutOfStock
var description: String{
switch self {
case .NoSuchItem: return "Not Such Item"
case .NotEnoughMoney(let price): return "Not Enough Money. " + String(price) + " Yuan needed."
case .OutOfStock: return "Out of Stock"
}
}
}
现在我们处理异常的方式可以有如下几种
Ps:可以抛出异常的函数类似于可选性,不能直接调用,因此要么用try,要么用do-catch
<1> try! 表示强制解析,确认一定没有异常,慎用!
pocketMoney = try! machine.vend(itemName: "Coca Cola", money: pocketMoney)
<2> try?表示如果没有异常就正常进行,不然就返回nil
try? machine.vend(itemName: "Coca Cola", money: pocketMoney)
<3> do-catch,do里面是正常逻辑,catch可以指定具体的错误类型,但是建议在最后加上一个catch什么也不接的,这样可以捕获所有异常,catch中可以也可以用let捕获错误里带有的值
do{
pocketMoney = try machine.vend(itemName: "Coca Cola", money: pocketMoney)
print(pocketMoney,"Yuan left")
}
catch VendingMachine.ItemError.NoSuchItem{
print("No Such Item")
}
catch VendingMachine.ItemError.NotEnoughMoney(let price){ // 这里可以获取抛出异常时自己带有的值
print("Not Enough Money." , price , "Yuan needed.")
}
catch VendingMachine.ItemError.OutOfStock{
print("Out of Stock")
}
catch{
print("Error occured during vending.")
}
<4> 如果想输出error的具体信息或者对error进行操作,也可以用catch let ... as语句,将错误转成自己定义的类型,并进行一定的操作
do{
pocketMoney = try machine.vend(itemName: "Coca Cola", money: pocketMoney)
print(pocketMoney,"Yuan left")
}
catch let error as VendingMachine.ItemError{
print(error)
}
catch{
print("Error occured during vending.")
}
4. defer关键字
写在函数里,一个函数里可以有多个,当且仅当函数退出作用域的时候运行,即正常return,或者抛出异常。
如果一个函数有多个defer,只有退出作用域那行代码之前的defer才起作用,并且执行顺序是倒序。
e.g.
func vend(itemName itemName: String, money: Int) throws -> Int{
defer{
print("Have a nice day")
}
guard let item = items[itemName] else{
throw VendingMachine.ItemError.NoSuchItem
}
guard money >= item.price else{
throw VendingMachine.ItemError.NotEnoughMoney(item.price)
}
guard item.count > 0 else{
throw VendingMachine.ItemError.OutOfStock
}
defer{ // 如果抛出异常了,这句话不会执行
print("Thank you")
}
dispenseItem(itemName: itemName)
return money - item.price
}