swift - 異常處理

來源:互聯網
上載者:User

標籤:就會   develop   nbsp   defer   cti   添加   崩潰   hand   蘋果   

Swift 對 Error Handling詳解

蘋果官方文檔解釋

跟其它語言一樣,Swift的異常處理是在程式拋出異常後的處理邏輯。 Swift提供了一流的異常拋出、捕獲和處理的能力。跟Java語言類似, Swift的異常並不是真正的程式崩潰, 而是程式啟動並執行一個邏輯分支;Swift和Java捕獲異常的時序也是一樣的。當Swift運行時拋出異常後並沒有被處理, 那麼程式就會崩潰。

在Swift語言中使用Error表示異常, 作用同Java的Exception類或Object-C的NSError類。 蘋果建議使用枚舉作為異常類型(為什麼不推薦用類或者結構體?答案是列舉資料型別本身就是分成若干種情況,很適合做邏輯分支判斷條件)。

enum VendingMathineError: Error {    case invalidSelection    case insufficientFunds(coinsNeed: Int)    case outOfStack}

上面聲明了枚舉類型VendingMathineError,繼承於Error。 注意Swift的所有異常類型都繼承於Error, 就像Java所有異常類都繼承於Exception一樣。

類似於Java處理異常的try/catch/finally, Swift提供了try、try?、try!、catch、throw、throws關鍵字處理異常邏輯,用法跟Java也很像。

 

如何聲明一個可能拋出異常的函數?  在函數參數括弧後面添加throws關鍵字, 跟Java文法有點像;區別是Swift的throws後面不用跟著異常類、而Java的throws後面要有異常類名稱。 你只要告訴Swift這個函數可能拋出異常就夠了,不需要說明到底是哪種異常,函數體內可以拋出任意類型的異常(肯定是繼承於Error)。

func canThrowErrors() throws -> String

 

func canThrowErrors(type: Int) throws -> String? {    //函數體寫成switch/case更好一些    if type == 1 {        throw VendingMathineError.invalidSelection    }    if type == 2 {        throw VendingMathineError.outOfStack    }    if type == 3 {        throw VendingMathineError.insufficientFunds(coinsNeed: 100)    }    return "success"}

 

上面測試代碼是為了測試拋異常邏輯, 函數體寫成switch/case更好一些。 從canThrowErrors函數看出,當參數為1、2或3時會拋異常, 文法是throw ... 且程式會跳出函數體,文法同Java。

 

Swift提供了一種類似於Java try/catch的文法, 是do(函數體內必須有try且該語句可能拋出異常)、catch。

 

 

do {try expression    statements} catch pattern 1 {    statements} catch pattern 2 where condition {    statements}

 

注意:如果try語句拋出異常則會跳出do代碼塊,並按順序逐個catch,當一個catch捕獲成功後,後面的catch不再執行。

 

do {    var data = try canThrowErrors(type: 3)//執行這個函數 這個函數可能拋出異常    print("after execute canThrowErrors")    if data != nil {        print("Error test data:\(data)")    }} catch VendingMathineError.outOfStack {    print("outOfStack")} catch VendingMathineError.invalidSelection {    print("invalidSelection")} catch {      //類似於Java的catch(Exception ex)    print("Error")}

 

輸出:Error

 

 

 

try canThrowsErrors(type: 3)會拋出VendingMathineError.isSufficientFunds(coinsNeed:100),不屬於前2個catch類型, 而最後一個catch是捕獲所有異常, 所有會執行其函數體。

      是不是感覺少了點什嗎? 對, 少了個類似於Java的finally,後面會介紹。 

      下面再介紹一下try?和try!的用法。

let x = try? someThrowingFunction()//與下面的相同let y: Int? do{       y = try someThrowingFunction()}catch {    y = nil}    

 

try?後面的語句可能會拋出異常, 如果拋出異常則賦值nil給左側;如果沒拋出異常則將傳回值賦給左側;

try!取消異常捕獲邏輯,文法有點任性,相當於裸奔, 明知可能拋出異常,但自信這段代碼不會拋異常。 try!是try?的補充。你確定後面語句不會拋出異常,但真的拋出異常後程式會崩潰。不建議使用try!,有使用情境推薦使用try?

 

let tmpX = try? canThrowErrors(type: 1)  //如果拋出異常程式正常運行並賦值nil給左側, 如果沒拋異常則將傳回值賦給左側//let tmpY = try! canThrowErrors(type: 2)  //你很確定不會拋出異常時這樣用,但如果運行時拋異常會導致程式崩潰

 

 

Swift使用defer關鍵字作用同Java的finally, 即使代碼塊內有break、continue、return或者拋異常,在結束代碼塊後仍然會執行defer代碼塊

下面代碼只是為了測試,驗證函式體內拋出異常時的執行時序, 文法邏輯跟finally一模一樣。

func testDefer(_ param: Int) throws -> String {    print("testDefer begin")
    defer {//拋出異常就執行defer 為拋出異常就最後執行defer        print("testDefer exit")    }

// do something...
    if param == 1 {        throw VendingMathineError.invalidSelection    }    print("testDefer end")return "testDefer return"    }//調用函數 該函數拋出異常tmpZ = nillet tmpZ = try? testDefer(1)

 

 

 

 

 輸出:testDefer begintestDefer exit

 

 

沒有 defer 拋出異常的執行邏輯

func testDeferNormal() {    print("testDefer begin")    defer {        print("testDefer exit")    }    print("testDefer end")}testDeferNormal()

 

swift - 異常處理

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.