Swift中的異常和錯誤處理1

異常處理基礎篇

只要我們在編程,就一定要面對錯誤處理的問題。其實,為了讓我們少犯錯誤,Swift在設計的時候就盡可能讓我們明確感知錯誤,明確處理錯誤。例如:

-只有使用Optional才能處理空值;

-switch...case...必須處理所有的請求;
總之,你處處能感受到Swift為你少犯錯的良苦用心。所以,當你真的要處理錯誤的時候,Swift當然更會要求你嚴謹處理。

如何描述一個錯誤?

在Swift里,任何一個遵從ErrorType protocol的類型,都可以用于描述錯誤。ErrorType是一個空的protocol,它唯一的功能,就是告訴Swift編譯器,某個類型用來表示一個錯誤。而通常,我們使用一個enum來定義各種錯誤。例如,假設我們有一個機器人類型,我們要定一個表達它工作狀態(tài)的錯誤:

enum RobotError: ErrorType {
    case LowPower(Double)
    case Overload(Double)}

其中LowPower表示電量低,它的associated value表示電量的百分比。而Overload表示超過負載,它的associated value表示最大負載值。

如何描述一個會發(fā)生錯誤的方法?

然后,我們來創(chuàng)建一個表示機器人的類:

class Robot {
     var power = 1.0
     let maxLifting = 100.0 // Kg
}

它有兩個屬性,power表示當前電量,maxLifting表示它可以舉起來的最大質(zhì)量。然后,我們添加一些可以發(fā)送給Robot的命令:

enum Command {
    case PowerUp
    case Lifting(Double)
    case Shutdown
}

Command中的三個case分別表示對Robot發(fā)送:啟動、舉重和關機三個命令。接下來,我們給Robot添加一個接受命令的方法 action。

class Robot {
    var power = 1.0
    let maxLifting = 100.0 // Kg

    func action(command: Command) throws { }
}

由于action有可能發(fā)生異常,對于這樣的方法,我們要明確使用throws關鍵字標記它。在action的實現(xiàn)里,我們用一個switch...case來遍歷Command:

class Robot {
    var power = 1.0
    let maxLifting = 100.0 // Kg

    func action(command: Command) throws {
        switch command {
        case .PowerUp:
            guard self.power > 0.2 else {
                throw RobotError.LowPower(0.2)
            }
            print("Robot started")
        case let .Lifting(weight):
            guard weight <= maxLifting else {
                throw RobotError.Overload(maxLifting)
            }
            print("Lifting weight: \(weight) KG")
        case .Shutdown:
            print("Robot shuting down...")
        }
    }
}

在action的實現(xiàn)里,當處理.PowerUp命令時,我們使用了guard確保Robot電量要大于20%,否則,我們使用throw RobotError.LowPower(0.2)的方式拋出了一個異常(throw出來的類型必須是ErrorType)。
處理.Lifting命令時,我們讀取了.Liftting的associated value,如果要舉起的質(zhì)量大于maxLifting,則throw RobotError.Overload(maxLifting)。
通常,guard和throw配合在一起,可以讓我們的代碼變的更加簡潔。

如何處理錯誤?

當我們調(diào)用了一個可能會拋出異常的方法時,我們一定要"通過某種方式"處理可能會發(fā)生的異常,如果你不處理,iOS會替你處理。當然,作為"代勞"的成本,iOS也會Kill掉你的app。因此,對于"業(yè)務邏輯類"的異常,我們還是自己處理好些,Swift允許我們使用三種方式處理異常。為了演示它們的用法,我們先來定義一個讓Robot工作的函數(shù),由于它會調(diào)用action,因此它也會拋出RobotError異常,我們也需要用throws來定義它:

func working(robot: Robot) throws {
}

do...catch...

在working的實現(xiàn)里,首先,我們要讓Robot"啟動":

func working(robot: Robot) throws {
    do { 
       try robot.action(Command.PowerUp)
}
    catch let RobotError.LowPower(percentage){
       print("Low power: \(percentage)")
    }
}

通過前面action的代碼我們知道,如果傳入的robot參數(shù)的"電量"低于20%,action會拋出異常,因此在working的實現(xiàn)里:

-我們必須在調(diào)用會拋出異常的方法前面使用try關鍵字;

-如果我們要捕獲方法拋出的異常,就需要把會拋出異常的代碼放在關鍵字do包含的代碼塊里;

-我們使用catch關鍵字匹配要捕捉的各種異常,例如在上面的例子里,我們捕捉了.LowPower,并且讀取了它的associated value;
如果我們要捕獲多個異常,就可以在do代碼塊后面,串聯(lián)多個catch,例如,我們添加一個讓Robot舉起某個東西的命令:

func working(robot: Robot) throws {
    do {
        try robot.action(Command.PowerUp)
        try robot.action(Command.Lifting(52))
    }
    catch let RobotError.LowPower(percentage) {
        print("Low power: \(percentage)")
    }
    catch let RobotError.Overload(maxWeight) {
        print("Overloading, max \(maxWeight) KG is allowd")
    }
}

我們就需要在do后面多串聯(lián)一個catch,用來捕獲Robot"超載"的異常。

錯、不錯都會執(zhí)行的代碼

在Swift的異常處理機制理,有一個允許我們添加無論代碼執(zhí)行正常與否,只要離開當前作用域,就一定會執(zhí)行的代碼。我們使用defer關鍵字來指定這樣的代碼。例如,我們給working添加一個defer,它用來讓Robot關機。

func working(robot: Robot) throws {
    defer {
        try! robot.action(Command.Shutdown)
    }
    do {
        try robot.action(Command.PowerUp)
        try robot.action(Command.Lifting(52))
    }
    catch let RobotError.LowPower(percentage) {
        print("Low power: \(percentage)")
    }
    catch let RobotError.Overload(maxWeight) {
        print("Overloading, max \(maxWeight) KG is allowd")
    }
}

斷言肯定不會錯噠~

在上面的defer代碼塊里,我們使用了"try!"這樣的形式。這是由于defer代碼塊中,不允許我們包含任何會跳出當前代碼塊的語句,例如:break / return / 拋出異常等。因此,我們使用try!告訴Swift我們確定這個調(diào)用不會發(fā)生異常(如果你對Swift說謊,是會引發(fā)運行時異常的 .)。
另外,使用"try!"標記的函數(shù)調(diào)用,可以不放在do代碼塊里。

把錯誤變成一個Optional

最后,我們調(diào)用working函數(shù),讓Robot完成工作:

let iRobot = Robot()
try? working(iRobot)

在這里,我們我們使用了"try?"的形式調(diào)用了一個會拋出異常的方法,它把表達式的評估結果轉(zhuǎn)換為一個Optional。例如,我們讓working返回一個Int:

func working(robot: Robot) throws -> Int {
    defer {
        try! robot.action(Command.Shutdown)
    }
    do {
        try robot.action(Command.PowerUp)
        try robot.action(Command.Lifting(52))
    }
    catch let RobotError.LowPower(percentage) {
        print("Low power: \(percentage)")
    }
    catch let RobotError.Overload(maxWeight) {
        print("Overloading, max \(maxWeight) KG is allowd")
    }
return 0
}

從上面的代碼里可以看到,當函數(shù)有返回值的時候,我們要把throws寫在返回值前面。
然后,我們查看working的返回值和類型:

let a = try? working(iRobot)
print("value: \(a)\n type: \(a.dynamicType)")

這里,由于我們處理異常,因此a的值是0,但是,a的類型,是一個Optional。

enter image description here
enter image description here

如果我們把RobotError.Overload注釋掉,然后讓Robot舉起超過100KG的物體:

func working(robot: Robot) throws -> Int {
    defer {
        try! robot.action(Command.Shutdown)
    }
    do {
        try robot.action(Command.PowerUp)
        try robot.action(Command.Lifting(152))
    }
    catch let RobotError.LowPower(percentage) {
         print("Low power: \(percentage)")
    }
    /*catch let RobotError.Overload(maxWeight) {
      print("Overloading, max \(maxWeight) KG is allowd")
    }*/
    return 0}

這樣異常就會被拋到working外圍,此時Swift運行時會捕捉到這個異常,并且,把a的值設置成nil:

let a = try? working(iRobot)
print("value: \(a)\n type: \(a.dynamicType)")
enter image description here
enter image description here

接下來?在下一段中,我們將向大家介紹多線程環(huán)境中的異常處理。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 六種異常處理的陋習 你覺得自己是一個Java專家嗎?是否肯定自己已經(jīng)全面掌握了Java的異常處理機制?在下面這段代...
    Executing閱讀 1,410評論 0 6
  • 轉(zhuǎn)載自:https://github.com/Tim9Liu9/TimLiu-iOS[https://github...
    香橙柚子閱讀 9,145評論 0 36
  • 我聽歌曲,一般有自己喜歡的歌單,很少跳到外面去,所以李榮浩已經(jīng)火了很多很多天,到現(xiàn)在我才知道。只第一遍,我就喜歡上...
    一號貓閱讀 594評論 1 1
  • 本書講述的事伊蘭特的,五個兒子擁有這上古武器的力量,每個人體內(nèi)都有神寄居在里面,被稱之為寄神者,也只有寄神者才能找...
    澀敘喵閱讀 391評論 3 4
  • 2017.08.23號,好熱的一天。朋友圈很多人都在曬明星羅志祥來平度的照片,本來也想look一下,到福安市場...
    愛孩子閱讀 304評論 0 1

友情鏈接更多精彩內(nèi)容