Swift 與 Objective-C

定義 Swift 自訂錯誤訊息:LocalizedError 完整整理(含範例)

使用 Swift 開發 App 時,是否曾經用 do-catch 捕捉錯誤,卻發現真正顯示在畫面上的訊息實在不太理想?

閱讀 4 分鐘
定義 Swift 自訂錯誤訊息:LocalizedError 完整整理(含範例) 封面圖

使用 Swift 開發 App 時,是否曾經用 do-catch 捕捉錯誤,卻發現真正顯示在畫面上的訊息實在不太理想?

如果直接使用 error.localizedDescription,使用者很容易看到像 “The operation couldn’t be completed…” 這種不明所以的文字。

先直接說結論。

在 Swift 中定義要顯示給使用者的自訂錯誤訊息時,請採用 LocalizedError 協定,而不是 Error,並實作 errorDescription 屬性。

今天就搭配範例,一步一步說明這個方法。


為什麼只使用 Error 不夠?

很多人會像這樣定義錯誤。

enum LoginError: Error {
    case invalidPassword
    case userNotFound
}

如果只做到這裡就輸出 error.localizedDescription,顯示的不是我們期待的「密碼錯誤」,而是系統產生的平淡預設訊息。

這是因為 Error 協定本身沒有定義人類可讀訊息的位置。

因此就有了 LocalizedError


如何定義 Swift 自訂錯誤訊息?

方法很簡單:採用 LocalizedError,並實作 errorDescription

以下是為登入錯誤加上使用者訊息的範例。

extension LoginError: LocalizedError {
    var errorDescription: String? {
        switch self {
        case .invalidPassword:
            return "密碼不正確."
        case .userNotFound:
            return "使用者不存在."
        }
    }
}

現在呼叫 error.localizedDescription 時,就會直接顯示我們定義的文字。

重點是,errorDescription 的回傳型別是 String?,也就是 Optional。

如果在這裡回傳 nil,就會再次回到系統的預設訊息。因此,為每個 case 填入值非常重要。

重點是為每個 case 填入字串。
重點是為每個 case 填入字串。

除了 errorDescription 之外還有其他選項嗎?(failureReason・recoverySuggestion)

有,LocalizedError 還有其他可選擇實作的屬性。

將它們的用途整理成表格如下。

屬性 用途 範例文字
errorDescription 哪裡出錯 「登入失敗。」
failureReason 為什麼發生 「密碼已輸入錯誤 5 次。」
recoverySuggestion 如何解決 「請稍後再試。」

特別是 recoverySuggestion,在引導使用者進行下一步操作時非常實用。

實際上,在 SwiftUI 的 Alert 或 AppKit 環境中,這些值有時還會被自動讀取並放到畫面上。

如果是面向使用者的錯誤,我通常至少會準備 errorDescriptionrecoverySuggestion 這兩項。


別把開發用紀錄與使用者訊息混為一談

最後再補充一點。

想記錄在除錯紀錄中的開發者說明,建議放在 CustomStringConvertible(也就是 description)中,

而顯示給使用者的翻譯訊息則放在 LocalizedError 中。

因為兩者的目的不同:一個是為了自己,另一個是為了使用者。

將職責分開後,日後要支援多語系時,也會更容易加入 NSLocalizedString


用一句話總結今天的內容:「如果是顯示給使用者的錯誤,就先填好 LocalizedErrorerrorDescription。」

一個小習慣就能大幅改變使用者體驗,請務必在下一個專案中試試看。為你加油!🙌


參考資料

延伸閱讀