How to provide a localized description with an Error type in Swift?
As described in the Xcode 8 beta 6 release notes,
Swift-defined error types can provide localized error descriptions by adopting the new LocalizedError protocol.
In your case:
public enum MyError: Error { case customError}extension MyError: LocalizedError { public var errorDescription: String? { switch self { case .customError: return NSLocalizedString("A user-friendly description of the error.", comment: "My error") } }}let error: Error = MyError.customErrorprint(error.localizedDescription) // A user-friendly description of the error.
You can provide even more information if the error is convertedto NSError
(which is always possible):
extension MyError : LocalizedError { public var errorDescription: String? { switch self { case .customError: return NSLocalizedString("I failed.", comment: "") } } public var failureReason: String? { switch self { case .customError: return NSLocalizedString("I don't know why.", comment: "") } } public var recoverySuggestion: String? { switch self { case .customError: return NSLocalizedString("Switch it off and on again.", comment: "") } }}let error = MyError.customError as NSErrorprint(error.localizedDescription) // I failed.print(error.localizedFailureReason) // Optional("I don\'t know why.")print(error.localizedRecoverySuggestion) // Optional("Switch it off and on again.")
By adopting the CustomNSError
protocol the error can providea userInfo
dictionary (and also a domain
and code
). Example:
extension MyError: CustomNSError { public static var errorDomain: String { return "myDomain" } public var errorCode: Int { switch self { case .customError: return 999 } } public var errorUserInfo: [String : Any] { switch self { case .customError: return [ "line": 13] } }}let error = MyError.customError as NSErrorif let line = error.userInfo["line"] as? Int { print("Error in line", line) // Error in line 13}print(error.code) // 999print(error.domain) // myDomain
I would also add, if your error has parameters like this
enum NetworkError: LocalizedError { case responseStatusError(status: Int, message: String)}
you can call these parameters in your localized description like this:
extension NetworkError { public var errorDescription: String? { switch self { case .responseStatusError(status: let status, message: let message): return "Error with status \(status) and message \(message) was thrown" }}
You can even make this shorter like this:
extension NetworkError { public var errorDescription: String? { switch self { case let .responseStatusError(status, message): return "Error with status \(status) and message \(message) was thrown" }}
There are now two Error-adopting protocols that your error type can adopt in order to provide additional information to Objective-C — LocalizedError and CustomNSError. Here's an example error that adopts both of them:
enum MyBetterError : CustomNSError, LocalizedError { case oops // domain static var errorDomain : String { return "MyDomain" } // code var errorCode : Int { return -666 } // userInfo var errorUserInfo: [String : Any] { return ["Hey":"Ho"] }; // localizedDescription var errorDescription: String? { return "This sucks" } // localizedFailureReason var failureReason: String? { return "Because it sucks" } // localizedRecoverySuggestion var recoverySuggestion: String? { return "Give up" }}