Swift 与 Objective-C

定义 Swift 自定义错误消息:LocalizedError 完整总结(含示例)

使用 Swift 开发应用时,你可能遇到过这样的情况:用 do-catch 捕获了错误,却发现真正显示在屏幕上的消息并不理想。

4 分钟阅读
定义 Swift 自定义错误消息:LocalizedError 完整总结(含示例) 封面图

使用 Swift 开发应用时,你可能遇到过这样的情况:用 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?,也就是可选类型。

如果在这里返回 nil,就会再次回到系统默认消息。因此,为每个 case 提供值非常重要。

关键是为每个 case 填入字符串。
关键是为每个 case 填入字符串。

除了 errorDescription,还有其他选项吗?(failureReason · recoverySuggestion)

有。LocalizedError 还包含其他可以选择实现的属性。

它们的作用可以整理成下面这张表。

属性 作用 示例消息
errorDescription 出了什么问题 “登录失败。”
failureReason 为什么发生 “密码已输错 5 次。”
recoverySuggestion 如何解决 “请稍后重试。”

尤其是 recoverySuggestion,在引导用户进行下一步操作时非常有用。

实际上,在 SwiftUI 的 Alert 或 AppKit 环境中,这些值甚至可以被自动读取并显示在屏幕上。

对于面向用户的错误,我通常至少会准备 errorDescriptionrecoverySuggestion


不要混淆开发日志和用户消息

最后再补充一点。

想记录在调试日志中的开发者说明,建议使用 CustomStringConvertible(也就是 description),

而显示给用户的翻译后消息则放在 LocalizedError 中。

因为两者的目的不同:一个是为我自己准备的,另一个是为用户准备的。

这样分离职责后,日后支持多语言时,添加 NSLocalizedString 也会容易得多。


用一句话总结今天的内容:“如果错误要显示给用户,就先填好 LocalizedErrorerrorDescription。”

一个小习惯就能显著改善用户体验,所以请务必在下一个项目中试试看。加油!🙌


参考资料

延伸阅读