如何让错误说用户的语言?
\n\nSwift开发者经常遇到一个问题:错误被抛出,但用户看到的是类似 Error Domain=MyApp Code=42 这样的信息。这在技术上是正确的,但对人来说完全无用。在Stack Overflow上,问题 "How to provide a localized description with an Error type in Swift?" 获得了数千次浏览——这并非偶然。
在本文中,我们将探讨如何将枯燥的错误代码转化为清晰、本地化的消息。您将了解如何使用 LocalizedError 协议、处理 NSError 以及如何正确准备不同语言的字符串。准备好让您的应用更友好了吗?让我们开始吧!
为什么单纯的Error不起作用?
\n\n在Swift中,Error 协议是一个最小契约。它既不要求描述,也不要求本地化。当您创建自己的错误时:
enum NetworkError: Error {\n case timeout\n case serverError(code: Int)\n}\n\n...您只会得到case的名称。尝试调用 localizedDescription:
let error = NetworkError.timeout\nprint(error.localizedDescription) // "The operation couldn’t be completed. (NetworkError error 0.)"\n\n系统会替换成标准短语——信息不足且不美观。为了给用户提供有意义的消息,您需要实现 LocalizedError 协议。
认识一下:LocalizedError协议
\n\nLocalizedError 扩展了 Error,并添加了四个可选属性:
- \n
errorDescription— 给用户的主要消息 \n failureReason— 错误原因(技术性) \n recoverySuggestion— 用户应该怎么做 \n helpAnchor— 帮助链接(很少使用) \n
最重要的是 errorDescription。系统组件(警告框、SwiftUI)正是显示这个属性。
实现本地化错误
\n\n为我们的 NetworkError 添加 LocalizedError:
enum NetworkError: LocalizedError {\n case timeout\n case serverError(code: Int)\n case noInternet\n \n var errorDescription: String? {\n switch self {\n case .timeout:\n return NSLocalizedString(\n "服务器无响应。请检查连接并重试。",\n comment: "Timeout error"\n )\n case .serverError(let code):\n let format = NSLocalizedString(\n "服务器错误:%d。请稍后重试。",\n comment: "Server error with code"\n )\n return String(format: format, code)\n case .noInternet:\n return NSLocalizedString(\n "没有互联网连接。",\n comment: "No internet error"\n )\n }\n }\n \n var failureReason: String? {\n switch self {\n case .timeout:\n return NSLocalizedString(\n "等待服务器响应超时。",\n comment: "Timeout reason"\n )\n case .serverError(let code):\n return NSLocalizedString(\n "服务器返回了代码 \\(code)。",\n comment: "Server error reason"\n )\n case .noInternet:\n return NSLocalizedString(\n "没有活跃的互联网连接。",\n comment: "No internet reason"\n )\n }\n }\n \n var recoverySuggestion: String? {\n switch self {\n case .timeout:\n return NSLocalizedString(\n "请检查Wi-Fi或移动数据,然后重试请求。",\n comment: "Timeout recovery"\n )\n case .serverError:\n return NSLocal