Swift(學習):錯誤處理(自定義錯誤,do-catch捕捉錯誤,處理Error,try?,try1,rethrows,defer,assert,fatalError)

錯誤類型

  • 開發過程常見的錯誤:
  1. 語法錯誤(編譯報錯)
  2. 邏輯錯誤 
  3. 運行時錯誤(可能會導致閃退,一般也叫做異常
  4. ......

自定義錯誤

  • Swift中可以通過Error協議自定義運行時的錯誤信息
enum SomeError : Error {
    case illegalArg(String)
    case outOfBounds(Int, Int)
    case outOfMemory
}
  • 函數內部通過throw拋出自定義Error,可能會拋出Error的函數必須加上throws聲明
func devide (_ num1: Int, _ num2: Int) throws -> Int {
    if num2 == 0 {
        throw SomeError.illegalArg("0不能做除數")
    }
    return num1 / num2
}
  • 需要使用try調用可能會拋出Error的函數
var result = try devide(20, 10)

do-catch

  • 可以使用do-catch捕捉Error
enum SomeError : Error {
    case illegalArg(String)
    case outOfBounds(Int, Int)
    case outOfMemory
}

func devide (_ num1: Int, _ num2: Int) throws -> Int {
    if num2 == 0 {
        throw SomeError.illegalArg("0不能做除數")
    }
    return num1 / num2
}

//var result = try devide(20, 10)

func test() {
    print("1")
    do {
        print("2")
        print("結果正確:",try devide(20, 2))
        print("3")
    } catch let SomeError.illegalArg(msg){
        print("參數異常:", msg)
    } catch let SomeError.outOfBounds(size, index) {
        print("下標越界:", "size=\(size)", "index=\(index)")
    } catch SomeError.outOfMemory {
        print("內存溢出")
    } catch {
        print("其他錯誤")
    }
    
    print("4")
}

test()
//結果爲
1
2
結果正確: 10
3
4

 上面對do-catch也可以簡寫爲:

也可以寫爲:

do {
   try divide(20, 0)
} catch {
    switch error {
    case let SomeError.illegalArg(msg):
        print("參數錯誤:", msg)
    default:
        print("其他錯誤")
    }
}

一旦捕獲到異常,try作用域內try之後的代碼將不會再執行,代碼如下:

enum SomeError : Error {
    case illegalArg(String)
    case outOfBounds(Int, Int)
    case outOfMemory
}

func devide (_ num1: Int, _ num2: Int) throws -> Int {
    if num2 == 0 {
        throw SomeError.illegalArg("0不能做除數")
    }
    return num1 / num2
}

//var result = try devide(20, 10)

func test() {
    print("1")
    do {
        print("2")
        print("結果正確:",try devide(20, 0))
        print("3")
    } catch let SomeError.illegalArg(msg){
        print("參數異常:", msg)
    } catch let SomeError.outOfBounds(size, index) {
        print("下標越界:", "size=\(size)", "index=\(index)")
    } catch SomeError.outOfMemory {
        print("內存溢出")
    } catch {
        print("其他錯誤")
    }
    
    print("4")
}

test()
//結果爲
1
2
參數異常: 0不能做除數
4

由上可以看出:一旦捕獲到異常,try作用域內try之後的代碼將不會再執行,比如do{ }方法內的print("3")就不會執行,但是try作用域外的可以執行,比如print("4")


處理Error

  • 處理Error的2種方式
  1. 通過do-catch捕捉Error
  2. 不捕捉Error,在當前函數增加throws聲明,Error將自動拋給上層函數 ,如果最頂層函數(main函數)依然沒有捕捉Error,那麼程序將終止
enum SomeError : Error {
    case illegalArg(String)
    case outOfBounds(Int, Int)
    case outOfMemory
}

func devide (_ num1: Int, _ num2: Int) throws -> Int {
    if num2 == 0 {
        throw SomeError.illegalArg("0不能做除數")
    }
    return num1 / num2
}

當頂層函數沒有捕捉Error,程序終止報錯如下:

 

捕捉Error的as書寫方式:

捕捉Error的is書寫方式:

 輸出結果:

  • 當錯誤處理被多個函數調用時,有兩種書寫方式:
//第一種
func test0() {
    test1()
}

func test1() {
    test2()
}

func test2() {
    do {
        print(try devide(200, 0))
    } catch is SomeError {
        print("This is SomeError")
    } catch {
        print("Error")
    }
}
//第二種
func test0() throws {
   try test1()
}

func test1() throws{
   try test2()
}

func test2() throws{
    do {
        print(try devide(200, 0))
    } catch is SomeError {
        print("This is SomeError")
    }
}

try test0()

try?、try!

  • 可以使用try?、try!調用可能會拋出Error的函數,這樣就不用處理Error

  • a、b是等價的

這裏可以看出當divide(20,0)拋出異常時,不會給b賦值,b爲nil,跑到catch也會賦值爲nil,所以a和b等價


rethrows

  • rethrows表明:函數本身不會拋出錯誤,但調用閉包參數拋出錯誤,那麼它會將錯誤向上拋

 

 此處的divide方法沿用之前的


defer

defer語句:用來定義以任何方式(拋錯誤、return等)離開代碼塊前必須要執行的代碼 

defer語句將延遲至當前作用域結束之前執行

  此處的divide方法沿用上面的

  • defer語句的執行順序與定義順序相反


assert(斷言)

  • 很多編程語言都有斷言機制,不符合指定條件就拋出運行時錯誤,常用於調試(Debug)階段的條件判斷
  • 默認情況下,Swift的斷言只會在Debug模式下生效,Release模式下會忽略

當v2 != 0時,會拋出錯誤

  • 增加Swift Flags修改斷言的默認行爲
  1. -assert-config Release:強制關閉斷言
  2. -assert-config Debug:強制開啓斷言

上圖是Debug模式下強制關閉斷言,和Release模式下強制開啓斷言


fatalError

  • 如果遇到嚴重問題,希望結束程序運行時,可以直接使用fatalError函數拋出錯誤(這是無法通過do-catch捕捉的錯誤)
  • 使用了fatalError函數,就不需要再寫return

  • 在某些不得不實現、但不希望別人調用的方法,可以考慮內部使用fatalError函數

  走到var stu2 = Student()運行時會報錯

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章