使用 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 填入值非常重要。
除了 errorDescription 之外還有其他選項嗎?(failureReason・recoverySuggestion)
有,LocalizedError 還有其他可選擇實作的屬性。
將它們的用途整理成表格如下。
| 屬性 | 用途 | 範例文字 |
|---|---|---|
errorDescription |
哪裡出錯 | 「登入失敗。」 |
failureReason |
為什麼發生 | 「密碼已輸入錯誤 5 次。」 |
recoverySuggestion |
如何解決 | 「請稍後再試。」 |
特別是 recoverySuggestion,在引導使用者進行下一步操作時非常實用。
實際上,在 SwiftUI 的 Alert 或 AppKit 環境中,這些值有時還會被自動讀取並放到畫面上。
如果是面向使用者的錯誤,我通常至少會準備 errorDescription 和 recoverySuggestion 這兩項。
別把開發用紀錄與使用者訊息混為一談
最後再補充一點。
想記錄在除錯紀錄中的開發者說明,建議放在 CustomStringConvertible(也就是 description)中,
而顯示給使用者的翻譯訊息則放在 LocalizedError 中。
因為兩者的目的不同:一個是為了自己,另一個是為了使用者。
將職責分開後,日後要支援多語系時,也會更容易加入 NSLocalizedString。
用一句話總結今天的內容:「如果是顯示給使用者的錯誤,就先填好 LocalizedError 的 errorDescription。」
一個小習慣就能大幅改變使用者體驗,請務必在下一個專案中試試看。為你加油!🙌
參考資料
- Create A Custom Swift Error [and override localizedDescription]
- Defining Custom Errors With Advanced Descriptions In Swift – SerialCoder.dev
- Alert and LocalizedError in SwiftUI – Augmented Code

