iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 28
0

Error Handling

程式開發過程中,難免會遇上錯誤,然而這些錯誤可能是些無法準確地知道什麼時候會發生的錯誤。

如果要讀取某個檔案中的資料,但是這個檔案不見得會存在,這時候就會因為找不到檔案,可能造成程式中斷或是卡死。

所以 Swift 提供了一些錯誤處理的方式,開發者可以先預想會發生什麼潛在的錯誤,當錯誤發生時,能夠收到錯誤訊息進而處理。

定義錯誤種類及錯誤拋出

要預防錯誤發生,最主要的還是程式碼要寫好 XD,但是有一種錯誤是不太能避免,比如說網路的問題或是資料的長短限制問題,針對這樣的錯誤,我們就可以先列舉出可能會發生的問題,將每一個問題當作為一種錯誤情況。

func validate(password: String) {
    guard password.count > 6 else {
        print("Password too short!")
        return
    }
    guard password.count <= 20 else {
        print("Password too long!")
        return
    }
    for character in password {
        guard character.isLetter else {
            print("\(character) is not letter!")
            return
        }
    }
}

定義錯誤種類

假使今天要做一個驗證密碼的判斷方法,針對密碼太短、太長或是密碼具有非法的字元作為限制條件,當遇到這些錯誤情況時,比較好的方式應該是拋出錯誤訊息,而不是直接 return,所以我們還可以這麼做:

enum PasswordValidationError: Error {
    case tooShort
    case tooLong
    case invalidCharacter(Character)
}

列舉出所有錯誤情況,並遵循 Error Protocol

那遵循 Error 協定可以幹嘛?

任何型別遵循 Error Protocol,就可被用來表示為 Swift 錯誤處理的情況。

那為什麼那要使用 Enumeration 呢?

在官方文件上有這麼一段話:

Swift enumerations are particularly well suited to modeling a group of related error conditions, with associated values allowing for additional information about the nature of an error to be communicated.

Enumeration 可以使用 case 來列舉錯誤情況,簡單也夠清楚,此外還可以使用 Associated Value 來提取錯誤的資訊。

錯誤拋出

所以針對錯誤處理,我們可以使用 throws 針對方法來使用,我們來看使用語法:

func 方法名稱(參數列) throws {
	...
}

透過 throws 來說明,這個方法是可以拋出錯誤的,那至於如何拋出錯誤,可以使用 throw

func validate(password: String) throws {
    guard password.count > 6 else {
        throw PasswordValidationError.tooShort
    }
    guard password.count <= 20 else {
        throw PasswordValidationError.tooLong
    }
    for character in password {
        guard character.isLetter else {
            throw PasswordValidationError.invalidCharacter(character)
        }
    }
}

透過 throw 關鍵字,將錯誤 case 丟出來。

錯誤處理

拋出來的錯誤要如何知道並且處理,靠的就是 do-catch 語法:

do {
    try 方法
    ...
} catch 錯誤1 {
    ...
} catch 錯誤2 {
    ...
}

透過 try 可以來抓取被丟出的錯誤訊息,依照不同的錯誤情況,用 catch 作為開頭一一分類:

func setPassword(_ password: String) {
    do {
        try validate(password: password)
        print("Success~")
    } catch PasswordValidationError.tooShort {
        print("Password too short!")
    } catch PasswordValidationError.tooLong {
        print("Password too long!")
    } catch PasswordValidationError.invalidCharacter(let character) {
        print("\(character) is not letter!")
    } catch {
        print("Unknown Error")
    }
}

設定密碼必須先判斷條件是否符合這些約束,如果不是的話就進行錯誤處理,是的話就印出 Success~

這裡要注意,如果不加上最後一個 catch,會直接噴一個錯誤訊息:Errors thrown from here are not handled because the enclosing catch is not exhaustive,意思就是說錯誤的檢查必須是 exhaustive,每個錯誤都要檢查到,就像是我們使用 Switch-Case,一樣的意思。


上一篇
Day 27 | Swift Protocol 與 Extension:Extension 篇
下一篇
Day 29 | Swift Generic Type
系列文
給我 30 天,給你一輩子:Swift 從零開始30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言