How to Provide a Localized Description With an Error Type in Swift

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.customError
print(error.localizedDescription) // A user-friendly description of the error.

You can provide even more information if the error is converted
to 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 NSError
print(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 provide
a 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 NSError

if let line = error.userInfo["line"] as? Int {
print("Error in line", line) // Error in line 13
}

print(error.code) // 999
print(error.domain) // myDomain

How to override localizedDescription for custom Error in Swift 3?

The documentation about new Error bridging feature is not clear enough still now, so this answer may need some updates in the near future, but according to SE-0112 and the latest Swift source code, you may need to use LocalizedError rather than Error and implement errorDescription.

class MyError: NSObject, LocalizedError {
var desc = ""
init(str: String) {
desc = str
}
override var description: String {
get {
return "MyError: \(desc)"
}
}
//You need to implement `errorDescription`, not `localizedDescription`.
var errorDescription: String? {
get {
return self.description
}
}
}

func test_my_code() {
let error = MyError(str: "my test string")
let x = error as Error
print(x.localizedDescription)
}
test_my_code() //->MyError: my test string

Other than using LocalizedError, this default implementation works:

(NSError.swift, the link shown above)

public extension Error {
/// Retrieve the localized description for this error.
var localizedDescription: String {
return NSError(domain: _domain, code: _code, userInfo: nil).localizedDescription
}
}

It is a little complicated how Swift defines _domain or _code from arbitrary types just conforming to Error, but it seems that NSError generates "The operation couldn’t be completed..." for unknown combinations of domain and code.

How can I show the localized description of an error in an error label format to a user in Swift?

The assignment must be the other way round. You are going to assign always the right side to the left side.

And you don’t need to create a string from a string

self.errorLabel.text = e.localizedDescription

Custom Error type initializer

Similarly as in How to provide a localized description with an Error type in Swift?
you can define a custom error type adopting the LocalizedError
protocol:

public struct MyError: Error {
let msg: String

}

extension MyError: LocalizedError {
public var errorDescription: String? {
return NSLocalizedString(msg, comment: "")
}
}

Example:

do {
throw MyError(msg: "Something happened")
} catch let error {
print(error.localizedDescription)
}

This prints the localized version of the given message.
Note that error in the catch-clause is a general Error, so
the caller does not need to cast it to the concrete error type (or even know
which error type is thrown).

How to get the string I put into a Error instance?

override errorDescription var

enum Error: LocalizedError {
case general(String)

var errorDescription: String? {
switch self {
case .general(let errorMessage):
return errorMessage
}
}
}

Now, you can also write do-catch block by this

do {
try foobar()
} catch let error {
print(error.localizedDescription)
}


Related Topics



Leave a reply



Submit