Swift 異常處理
異常的由來
在寫程式碼的過程中,我們不能保證自己的每一行程式碼,都能夠正確地執行。不能保證每一個函式,都會返回我們所期望的值。所以很多程式語言,都引入了異常處理
機制,來讓我們得知執行失敗的原因,從而可以做出應對。
舉例:在讀取某個磁碟中的檔案時,可能遇到
開啟磁碟失敗
,檔案不存在
等錯誤。
使用可選來處理簡單的異常
在 Swift 中有可選
的機制,可以解決函式返回不成功的問題,我們經常寫出如下程式碼:
/// 計算
func caculator() -> Double? {
// XXX
}
然後呼叫這個函式
if let result = caculator() {
print(result)
} else {
print("計算錯誤")
}
通過可選
機制,可以應對一些簡單的錯誤處理。當返回了正確的值,我們可以進行下一步操作,當返回nil
,則表示計算過程中發生了錯誤。但是當出現問題的原因比較多的時候,nil
的表現力就顯得很弱。所以,接下來介紹異常處理
。
認識異常處理
假設有這樣一個場景:汽車啟動,當使用的鑰匙正確,才能開啟汽車。當燃油大於5升才可以成功啟動,否則啟動不成功。
我們首先定義一個列舉,來描述汽車啟動失敗可能的每種情況。針對燃油不足的情況,我們還設定了關聯值來提醒使用者還差多少油才能啟動。
// 描述汽車出問題的各種情況
enum CarError: Error {
case keyError // 鑰匙不對
case outOfFuel(fuelNeed: Double) // 燃油不足
}
接著定義汽車模型。
struct Car {
// 當前燃油
var fuelInLitre: Double
// 汽車的鑰匙
var keyName: String
// 啟動汽車
func start() throws -> String {
guard keyName == "trueKey" else {
throw CarError.keyError
}
guard fuelInLitre > 5 else {
throw CarError.outOfFuel
}
return "啟動成功"
}
}
假設正確的鑰匙名稱為trueKey
。這裡使用了throws
關鍵字,來表示start
方法在執行過程中,可能會丟擲異常。throws
需要寫在->
前面。
接著,嘗試呼叫以上的程式碼。
let car = Car(fuelInLitre: 6, keyName: "trueKey")
do {
let message = try car.start()
print(message)
} catch CarError.keyError {
print("鑰匙不正確")
} catch CarError.outOfFuel(let fuelNeed) {
print("燃油不足,還需要:\(fuelNeed)")
} catch {
print("發生了其他錯誤")
}
我們先是定義了一個Car
的例項,接著嘗試呼叫start
方法,因為這個方法可能會丟擲異常,所以必須包含在do
的程式碼塊裡面,在呼叫方法前面加上try
關鍵字。呼叫完畢後,我們就當這個方法能呼叫成功,繼續寫成功之後的程式碼,輸出啟動資訊。
接著使用catch
關鍵字,來捕獲可能丟擲的異常,並對異常進行處理,我們可能會列印錯誤日誌,或者提示一些有用的資訊。
事實上我們只定義了兩種可能發生的異常,但是編譯時Xcode 9
會報錯,必須在最後面再加一個catch
來表示發了生其他的錯誤,有點類似於switch
語句最後那個default
。
其他補充
除了try
關鍵字,還有try?
和try!
關鍵字。try?
和可選機制很類似,當方法丟擲異常,就會返回一個nil
。
還是上面汽車啟動的例子,我們可以這樣寫:
let car = Car(fuelInLitre: 3, keyName: "trueKey")
if let message = try? car.start() {
print(message)
} else {
print("啟動錯誤,具體原因不知")
}
就不去判斷那麼多的異常情況,如果返回nil
,就代表發生了異常,具體原因不關心。
try!
關鍵字和強制解包很類似,當你認為某個方法一定能執行成功不會丟擲異常時,就用它。但是萬一丟擲了異常,那麼程式就崩潰。
let car = Car(fuelInLitre: 6, keyName: "trueKey")
// 強制執行,如果失敗,程式直接崩潰
let message = try! car.start()
print(message)
在介紹defer
關鍵字之前,假設:當我們嘗試開啟一輛汽車,無論啟動成功,或是啟動失敗,都會在最後關閉車門。首先為Car
模型新增一個方法closeDoor()
。
func closeDoor() {
print("關好車門")
}
然後使用defer
關鍵字,呼叫。
// 開啟了汽車的車門
let car = Car(fuelInLitre: 6, keyName: "trueKey")
// 延時執行,無論 start 方法執行成功或者失敗,我們都呼叫方法來關閉車門
defer {
car.closeDoor()
}
do {
let message = try car.start()
print(message)
} catch CarError.keyError {
print("鑰匙不正確")
} catch CarError.outOfFuel(let fuelNeed) {
print("燃油不足,還需要:\(fuelNeed)")
} catch {
print("發生了其他錯誤")
}
defer
關鍵字,當你的程式碼無論是正常的執行了,或者是丟擲了異常,都會去呼叫defer
程式碼塊裡面的語句,多用於做一些清理的工作。
上面的例子比較牽強,另外舉一個十分常見的場景:我們嘗試開啟磁碟,去讀取某個檔案時,無論讀取成功還是失敗,都會在最後關閉磁碟。
相關文章
- Swift Json 解析異常處理SwiftJSON
- 異常篇——異常處理
- 異常處理
- 異常-throws的方式處理異常
- 異常處理與異常函式函式
- JavaScript 異常處理JavaScript
- ThinkPHP 異常處理PHP
- React 異常處理React
- 08、異常處理
- JAVA 異常處理Java
- JAVA異常處理Java
- Abp 異常處理
- oracle異常處理Oracle
- PowerShell 異常處理
- plsql異常處理SQL
- JS異常處理JS
- app異常處理APP
- Oracle 處理異常Oracle
- MySQL異常處理MySql
- 異常處理 (轉)
- golang - 異常處理Golang
- 異常處理2
- 異常處理1
- 異常的處理
- Java 異常處理Java
- 異常處理機制(二)之異常處理與捕獲
- JSP 異常處理如何處理?JS
- Java 異常表與異常處理原理Java
- restframework 異常處理及自定義異常RESTFramework
- windows核心程式設計---未處理異常,向量化異常處理與C++異常Windows程式設計C++
- Python異常處理Python
- PHP 核心 - 異常處理PHP
- Python——異常處理Python
- JAVA_異常處理Java
- SpringMVC異常處理SpringMVC
- 異常處理過程
- C++ 異常處理C++
- PL SQL異常處理.SQL