一.異常的介紹
只要我們在編程,就一定要面對錯誤處理的問題。
Swift在設計的時候就盡可能讓我們明確感知錯誤,明確處理錯誤
比如:只有使用Optional才能處理空值;
如何描述一個錯誤?
在Swift里,任何一個遵從ErrorType protocol的類型,都可以用于描述錯誤。
ErrorType是一個空的protocol,它唯一的功能,就是告訴Swift編譯器,某個類型用來表示一個錯誤。
通常,我們使用一個enum來定義各種錯誤的可能性
二.異常的示例
假如我們想要讀取一個文件中的內容,按照OC的邏輯我們可以這樣來模擬
當我們調用方法獲取結果為nil時,你并不能確定到底參數了什么錯誤得到了nil
func readFileContent(filePath : String) -> String? {
// 1.filePath為
if filePath == "" {
return nil
}
// 2.filepath有值,但是沒有對應的文件
if filePath != "/User/Desktop/123.plist" {
return nil
}
// 3.取出其中的內容
return "123"
}
readFileContent("abc")
- 使用異常對上述方法進行改進
// 1.定義異常
enum FileReadError : ErrorType {
case FileISNull
case FileNotFound
}
// 2.改進方法,讓方法拋出異常
func readFileContent(filePath : String) throws -> String {
// 1.filePath為""
if filePath == "" {
throw FileReadError.FileISNull
}
// 2.filepath有值,但是沒有對應的文件
if filePath != "/User/Desktop/123.plist" {
throw FileReadError.FileISNull
}
// 3.取出其中的內容
return "123"
}
三.處理異常有三種方式
3.異常的處理三種方式
3.1.try方式,需要手動處理異常
do {
let result = try readFileContent("abc")
} catch {
print(error)
}
3.2.try?方式,不處理異常,如果出現了異常,則返回一個nil.沒有異常,則返回對應的值
最終返回結果為一個可選類型
let result = try? readFileContent("abc")
3.3.try!方法,告訴系統該方法沒有異常.
注意:如果出現了異常,則程序會崩潰
try! readFileContent("abc")
如何拋出異常
在拋出異常之前,我們需要在函數或方法的返回箭頭 -> 前使用 throws 來標明將會拋出異常
func myMethodRetrunString() throws -> String
// No return, we can just add throws in the end
func myMethodRetrunNothing() throws
聲明之后, 我們需要在函數或者方法里扔出異常,很簡單使用throw 就可以了
func myMethod() throws
//...
// item is an optional value
guard let item = item else {
// need throws the error out
throw MyError.NotExist
}
// do with item
}
上面這段代碼使用了guard
來進行unwrap optional value。這是 Swift 2.0 提供的一個新的方法。
Guard
在 Haskell, Erlang 等語言中早已存在guard
, 在這里有更多關于它的介紹。
guard
翻譯過來可以理解為守護,守衛。
在 Swift 中,guard
有點像if
但是他們有兩個非常重要的區別
guard
必須強制有else
語句
只有在guard
審查的條件成立,guard
之后的代碼才會運行 (像守衛一樣,條件不符就不讓過去)。
guard
中的else
只能執行轉換語句,像return
,break
,continue
或者throws
當然你也可以在這里返后一個函數或者方法。
值得注意的是,guard
的使用會提高你代碼的可讀性,但是也代表你的代碼的執行會有非常明確的順序性,這一點需要開發者們留心處理。
雖然我們在異常處理中提到了guard
但是不代表它只能在異常處理中使用。它具有廣泛的適用性,或許過陣子我會專門為guard
的使用寫篇文章。
如何獲取并處理異常?
上文講述了如何建造拋出異常,獲取和處理異常就變得很簡單了。使用do-catch
機制。
文/阮超(簡書作者)原文鏈接:http://www.lxweimin.com/p/96a7db3fde00著作權歸作者所有,轉載請聯系作者獲得授權,并標注“簡書作者”。
do {
try functionWillThrowError()
} catch {
// deal with error
}
do-catch
機制簡單易懂。很多編程語言也使用類似的機制進行異常處理,但是在 Swift 中有一個比較重要的特性。
catch
和switch
一樣具有 Pattern Matching 的能力。所以,使用catch
你可以對異常的解析進行更為高級的處理
文/阮超(簡書作者)原文鏈接:http://www.lxweimin.com/p/96a7db3fde00著作權歸作者所有,轉載請聯系作者獲得授權,并標注“簡書作者”。
do {
try functionWillThrowError()
} catch MyError.NotExist {
// deal with not exist
} catch MyError.OutOfRange {
// deal with not exist
}
這里值得提一下在 Swift 2.0中一個跟異常處理沒有關系的改進
Swift 2.0 中沒有了 do-while循環,取而代之的是 repeat-while。蘋果說這個改動是為了增強代碼的可讀性。但是我更覺得是為了讓我們更舒服的使用 do-catch
不處理異常
如果我不想處理異常怎么辦,或者說,我非常確定某個方法或者函數雖然聲明會拋出異常,但是我自己知道我在使用時候是絕對不會拋出任何異常的。這種情況下 我們可以使用 try!
文/阮超(簡書作者)
原文鏈接:http://www.lxweimin.com/p/96a7db3fde00
著作權歸作者所有,轉載請聯系作者獲得授權,并標注“簡書作者”。
try! functionThrowErrorNil()
當然,如果你使用 try!,而你的方法或者函數拋出了異常,那么你會得到一個運行中異常 (runtime error) 所以我們開發者需要慎用哦。
Defer
文章結束前我們再討論下 defer
在你的代碼塊就要結束前。如果你使用了 defer。 在其之中的代碼就會運行。等于說,給了你最后的機會來進行一些處理。如果你熟悉 BDD 或者 TDD, 那么你可以參考他們中的 aferAll 機制
文/阮超(簡書作者)
原文鏈接:http://www.lxweimin.com/p/96a7db3fde00
著作權歸作者所有,轉載請聯系作者獲得授權,并標注“簡書作者”。
func myFunction() throws {
defer {
// No matter what happened I need do something
print("All done, clean up here")
}
guard let item = item else {
// need throws the error out
throw MyError.NotExist
}
guard item.count > maxNumber else {
// need throws the error out
throw MyError.OutOfRange
}
// do something with item
// ...
}
注意,如果你有多個defer 語句,他們在執行的順序會和棧一樣,最后一個進,第一個出.
總結
使用 ErrorType 的幫助建立你的異常類型
使用 throws 來聲明異常,用 throw 來拋出異常
使用 do-catch 機制來獲取和處理異常