Swift:錯誤處理專題
阿新 • • 發佈:2018-12-12
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
}