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)用了一個會拋出異常的方法净捅,它把表達式的評估結果轉換為一個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)境中的異常處理恋追。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市罚屋,隨后出現(xiàn)的幾起案子苦囱,更是在濱河造成了極大的恐慌,老刑警劉巖脾猛,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撕彤,死亡現(xiàn)場離奇詭異,居然都是意外死亡猛拴,警方通過查閱死者的電腦和手機羹铅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愉昆,“玉大人职员,你說我怎么就攤上這事□烁龋” “怎么了焊切?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芳室。 經(jīng)常有香客問我专肪,道長,這世上最難降的妖魔是什么堪侯? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任嚎尤,我火速辦了婚禮,結果婚禮上伍宦,老公的妹妹穿的比我還像新娘芽死。我一直安慰自己,他們只是感情好雹拄,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布收奔。 她就那樣靜靜地躺著,像睡著了一般滓玖。 火紅的嫁衣襯著肌膚如雪坪哄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音翩肌,去河邊找鬼模暗。 笑死,一個胖子當著我的面吹牛念祭,可吹牛的內(nèi)容都是我干的兑宇。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼粱坤,長吁一口氣:“原來是場噩夢啊……” “哼隶糕!你這毒婦竟也來了?” 一聲冷哼從身側響起站玄,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤枚驻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后株旷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體再登,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年晾剖,在試婚紗的時候發(fā)現(xiàn)自己被綠了锉矢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡齿尽,死狀恐怖沽损,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情循头,我是刑警寧澤缠俺,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站贷岸,受9級特大地震影響壹士,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜偿警,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一躏救、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧螟蒸,春花似錦盒使、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至诵原,卻和暖如春英妓,著一層夾襖步出監(jiān)牢的瞬間挽放,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工蔓纠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辑畦,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓腿倚,卻偏偏與公主長得像纯出,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子敷燎,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

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