Swift 錯(cuò)誤處理(Error handling)

可選類型

在swift程序中我們會(huì)處理各種各樣的錯(cuò)誤,比如說(shuō)解析一個(gè)Dictionary:

  let dic = ["key": "value"]
  let value = dic["key"]

value實(shí)際上是一個(gè)optional類型都许,也就是說(shuō)value可能為String類型也可能是nil缆娃,處理這種情況我們一般對(duì)value嘗試解包,如果成功就取里面的值:

    if let value = dic["key"] {
       print(value)
    }

使用可選類型進(jìn)行錯(cuò)誤處理是一種方式段标,但是使用這種錯(cuò)誤處理方式有一定的局限性拐辽。比如說(shuō)我們想連接網(wǎng)絡(luò),如果沒(méi)有連接上就返回一個(gè)nil佛吓,雖然可以但是我們只知道網(wǎng)絡(luò)沒(méi)連接上宵晚,但是卻不知道沒(méi)連接上的原因到底是服務(wù)端超時(shí)呢,還是客戶端出現(xiàn)了問(wèn)題辈毯,所以使用一套完善的錯(cuò)誤處理機(jī)制能幫助我們更好的管理錯(cuò)誤坝疼。

表示并拋出錯(cuò)誤

舉一個(gè)例子,假如我們需要讀取磁盤上的某個(gè)文件進(jìn)行處理谆沃,這個(gè)任務(wù)可能會(huì)有多種失敗的情況钝凶,包括指定路徑下文件并不存在,指定文件類型不正確等唁影。我們的代碼看起來(lái)是這樣的:

class FileManager {

  struct File: CustomStringConvertible {
      let name: String
      let type: String
      let isReadable: Bool
      let size: Int
    
      var description: String {
          return "\(name).\(type) size is : \(size) Bytes"
      }
  }

  private var files = ["path1": File(name: "file1", type: "text", isReadable: true, size: 3096),
                     "path2": File(name: "file2", type: "mp3", isReadable: false, size: 10240),
                     "path3": File(name: "file3", type: "flv", isReadable: true, size: 20480)
                     ]

  func readFile(path: String, type: String) -> File? {
    
      // 檢查文件是否存在
      guard let file = files[path] else {
         return nil
      }
    
      // 檢查文件是否有可讀權(quán)限
      guard file.isReadable == true else {
          return nil
      }
    
      // 檢查文件類型
      guard file.type == type else {
          return nil
      }
    
      return file
  }
}

我們定義了一個(gè)FileManager類耕陷,它有一個(gè)readFile(path: String, type: String) -> File? 方法,該方法傳遞一個(gè)路徑和文件類型据沈,返回一個(gè)可選類型哟沫,如果文件不存在或者沒(méi)有可讀權(quán)限或者類型不匹配都會(huì)返回nil,但是這并不是我們的想要的結(jié)果锌介,我們想要的是讀取文件失敗的原因嗜诀。

在swift中,錯(cuò)誤用符合ErrorType協(xié)議的的類型的值來(lái)表示孔祸。代表一個(gè)可以拋出錯(cuò)誤的類型隆敢。

  • 我們可以使用枚舉來(lái)定義錯(cuò)誤類型:

      enum ReadFileError: ErrorType {
        case FileNotExists   // 文件不存在
        case FileIsReadable  // 沒(méi)有可讀權(quán)限
        case TypeMismatch    // 類型不匹配
      }
    
  • 然后我們修改readFile()方法

    func readFile(path: String, type: String) throws -> File? {
      
      // 檢查文件是否存在
      guard let file = files[path] else {
          throw ReadFileError.FileNotExists
      }
      
      // 檢查文件是否有可讀權(quán)限
      guard file.isReadable == true else {
          throw ReadFileError.FileNotReadable
      }
      
      // 檢查文件類型
      guard file.type == type else {
          throw ReadFileError.TypeMismatch
      }
      
      return file
    }
    
  • 注意需要在返回類型->前面加上throws關(guān)鍵字,代表這是一個(gè)可能拋出異常的方法崔慧。

  • 然后在guard語(yǔ)句的else條件里面拋出錯(cuò)誤拂蝎,這樣我們就能知道讀取文件失敗是什么原因?qū)е碌牧恕?/p>

處理錯(cuò)誤

readFile(path: String, type: String)方法會(huì)傳遞出它拋出的所有錯(cuò)誤,所有你要么使用do-catch語(yǔ)句惶室,要么將錯(cuò)誤繼續(xù)傳遞下去温自。

    1. throwing函數(shù)傳遞錯(cuò)誤

比如我們想讀取一個(gè)text類型的文件,我們的代碼可能是這樣的:

func readTextFile(path: String) throws -> File? {
    return try readFile(path, type: "text")
}

然后我們嘗試讀取一個(gè).text的文件:

let fileManager = FileManager()
if let file = try fileManager.readTextFile("path1") {
    print(file.description)
}

打印出:
file1.text size is : 3096 Bytes

    1. 使用do-catch進(jìn)行錯(cuò)誤處理
do {
    try fileManager.readFile("noSuchFilePath", type: "text")
} catch {
    print(error)
}

打印出FileNotExists文件不存在的錯(cuò)誤皇钞。

如果我們想對(duì)具體的錯(cuò)誤進(jìn)行處理悼泌,可以這樣:

  do {
      try fileManager.readFile("noSuchFilePath", type: "text")
  } catch ReadFileError.FileNotExists {
      print("File Not Exists")
  } catch ReadFileError.FileNotReadable {
      print("File Not Readable")
  } catch ReadFileError.TypeMismatch {
      print("Type Not Matched")
  } catch {
      print("unkown error")
  }

別忘了在處理了所有錯(cuò)誤之后在添加一個(gè)catch,因?yàn)橛锌赡軙?huì)有其他異常出現(xiàn)鹅士。

如果我們的錯(cuò)誤很多券躁,難免會(huì)寫很多catch語(yǔ)句,可以這樣處理:

do {
    try fileManager.readFile("noSuchFilePath", type: "text")
} catch let error as ReadFileError {
    // 使用 switch 進(jìn)行處理錯(cuò)誤
} catch {
    print("Unkown Error")
}

使用as關(guān)鍵字將ErrorType類型轉(zhuǎn)換成ReadFileError 類型掉盅。

defer語(yǔ)句

defer表示即將在離開(kāi)當(dāng)前代碼塊時(shí)執(zhí)行操作也拜。該語(yǔ)句讓你能執(zhí)行一些必要的清理工作,不管是以何種方式離開(kāi)當(dāng)前代碼塊的——無(wú)論是由于拋出錯(cuò)誤而離開(kāi)趾痘,還是由于諸如return或者break的語(yǔ)句慢哈。例如,你可以用defer語(yǔ)句來(lái)確保文件描述符得以關(guān)閉永票,以及手動(dòng)分配的內(nèi)存得以釋放卵贱。

func processFile(file: File) {
    
    file.open()
    
    defer {
        file.close()
    }

    // 可能拋出錯(cuò)誤的代碼
    // ...
    // ...
}

比如上面(偽代碼)我們讀取了一個(gè)文件,然后需要對(duì)該文件進(jìn)行調(diào)用open()侣集,處理完之后我們需要關(guān)閉close()键俱,但是中間可能會(huì)拋出錯(cuò)誤,導(dǎo)致我們的文件打開(kāi)了沒(méi)有關(guān)閉世分,使用defer就能確保close()操作會(huì)被執(zhí)行编振。代碼塊里面可以使用多個(gè)defer

實(shí)際上defer是控制轉(zhuǎn)移類關(guān)鍵字臭埋,它被當(dāng)做其他語(yǔ)言(例如java)的finally關(guān)鍵字來(lái)使用踪央。

值得一提的是,當(dāng)代碼塊里面有過(guò)多的控制轉(zhuǎn)移這類的語(yǔ)句時(shí)瓢阴,反而會(huì)導(dǎo)致程序非常的亂畅蹂、可讀性變差,所以一定要適當(dāng)?shù)氖褂谩?/p>

以此紀(jì)錄swift學(xué)習(xí)之旅荣恐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末液斜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子叠穆,更是在濱河造成了極大的恐慌少漆,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痹束,死亡現(xiàn)場(chǎng)離奇詭異检疫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)祷嘶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門屎媳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人论巍,你說(shuō)我怎么就攤上這事烛谊。” “怎么了嘉汰?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵丹禀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)双泪,這世上最難降的妖魔是什么持搜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮焙矛,結(jié)果婚禮上葫盼,老公的妹妹穿的比我還像新娘。我一直安慰自己村斟,他們只是感情好贫导,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蟆盹,像睡著了一般孩灯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逾滥,一...
    開(kāi)封第一講書(shū)人閱讀 51,578評(píng)論 1 305
  • 那天峰档,我揣著相機(jī)與錄音,去河邊找鬼匣距。 笑死面哥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的毅待。 我是一名探鬼主播尚卫,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼尸红!你這毒婦竟也來(lái)了吱涉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤外里,失蹤者是張志新(化名)和其女友劉穎怎爵,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體盅蝗,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鳖链,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了墩莫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芙委。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖狂秦,靈堂內(nèi)的尸體忽然破棺而出灌侣,到底是詐尸還是另有隱情,我是刑警寧澤裂问,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布侧啼,位于F島的核電站纵顾,受9級(jí)特大地震影響沟堡,放射性物質(zhì)發(fā)生泄漏誓篱。R本人自食惡果不足惜撩荣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望符喝。 院中可真熱鬧闪彼,春花似錦甜孤、人聲如沸协饲。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)茉稠。三九已至,卻和暖如春把夸,著一層夾襖步出監(jiān)牢的瞬間而线,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工恋日, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留膀篮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓岂膳,卻偏偏與公主長(zhǎng)得像誓竿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谈截,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

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