首先要明白拋出異常后異常的運動:異常被拋出后,中斷整個處理,異常不斷向外層(范圍)傳遞,直到遇到catch代碼塊群,會與catch代碼塊的條件進行匹配,匹配符合則進入此代碼塊處理。如果遇到沒有條件的catch{}那么直接在這個代碼里處理。如果拋出的異常一直到最外層仍沒有被catch{}處理,那么程序會卡住(后面的處理全部中斷)
enum numTest: Int, Error {
case _0, _1, _2, _3
case nothing = 999
}
func errorTest(by num: Int) throws -> String {
switch num {
case 0:
throw numTest._0
case 1:
throw numTest._1
case 2:
throw numTest._2
case 3:
throw numTest._3
case 10:
throw numTest.nothing
default:
return "OK" + " \(num)"
}
}
我們用這一段代碼來測試
print("即將開始測試")
try errorTest(by: 0)
print("測試結束")
print("因為異常沒有被捕捉,所以這兩句話不會運行")
運行結果如下:
即將開始測試
換言之,如果我們拋出了異常,那就必須進行處理,不想處理?那么就加個空的無條件的catch{},為了方便觀測效果,我們在catch里輸出測試中
print("即將開始測試")
do {
try errorTest(by: 0)
}catch {
print("---測試中---")
}
print("測試結束")
print("因為異常被捕捉,所以這兩句話會運行")
運行結果如下:
即將開始測試
---測試中---
測試結束
因為異常被捕捉,所以這兩句話會運行
由以上測試可知,拋出的異常必須被處理,不然異常會導致程序中斷,出現假死現象
可是,每次都要加上do-catch這一長串,無論是從代碼的可讀性還是寫代碼的角度都是非常不好的。這里,try?與try!就可以大顯身手了
其實到這里,相信大家也很清楚try?和try!的作用了。
沒錯,try?是一個可選綁定,當后面運行的可以拋出異常的函數沒有拋出異常,則直接運行。當拋出異常,則跳過此函數。既然是可選綁定,那么如果用在條件里,如果沒拋出異常,那么返回的值帶入聲明量(void返回的是void的空值,不是nil),如果拋出,可選綁定判定為false,和普通的可選綁定一樣
先看下面這個例子
print("即將開始測試")
try? errorTest(by: 0)
print("測試結束")
運行結果如下:
即將開始測試
測試結束
把try?改成try
print("即將開始測試")
try errorTest(by: 0)
print("測試結束")
運行結果如下:
即將開始測試
帶入條件
for i in 0 ..< 10 where i == 3 || i == 5 {
//for i in [3, 5] {
print("即將開始測試")
if let myTest = try? errorTest(by: i) {
print("測試中,", terminator: "")
print("沒有拋出異常, 測試值\(myTest)")
}else {
print("測試中,", terminator: "")
print("拋出異常")
}
print("測試結束")
print("-----------")
}
運行結果如下:
即將開始測試
測試中,拋出異常
測試結束
-----------
即將開始測試
測試中,沒有拋出異常, 測試值OK 5
測試結束
-----------
最后再來看看try!,這個很明顯了,就是默認不會拋出異常,直接運行,如果拋出運行在編譯出錯
print("即將開始測試")
print("正常值: ", try! errorTest(by: 6))
print("測試結束")
運行結果如下:
即將開始測試
正常值: OK 6
測試結束
最后總結一下,try?和try!主要用在對異常拋出函數進行不需要捕捉異常的處理。當然,一般不建議用try!,后期容易出問題