How to override localizedDescription for custom Error in Swift 3?

13,951

Solution 1

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.

Solution 2

If custom type conforms to protocol CustomStringConvertible and provides localized description, then the following extension of LocalizedError might be useful:

extension LocalizedError where Self: CustomStringConvertible {

   var errorDescription: String? {
      return description
   }
}

Example code:

class MyError: LocalizedError, CustomStringConvertible {

   let desc: String

   init(str: String) {
      desc = str
   }

   var description: String {
      let format = NSLocalizedString("Operation error: %@", comment: "Error description")
      return String.localizedStringWithFormat(format, desc)
   }
}


let error = MyError(str: "my test string")
let x = error as Error
print(x.localizedDescription) // Prints "Operation error: my test string"
print(String(describing: x))  // Prints "Operation error: my test string"
Share:
13,951
Maxim Kholyavkin
Author by

Maxim Kholyavkin

Want me to hire? I do not work with fixed price. Only hourly/part time/full time. I care about code quality and my rate begin from 40$ per hour. All my opensource code is available with two links: https://bitbucket.org/Speakus/ https://github.com/Speakus/ You could contact me via skype:speakus.net or same gmail user. Telegram: @Speakus

Updated on June 27, 2022

Comments

  • Maxim Kholyavkin
    Maxim Kholyavkin about 2 years

    Error protocol has only one property localizedDescription. I tried to create custom object inherited from NSObject and Error but I can not override localizedDescription. How can I do that?

    This code does not allow me to get custom description:

    class MyError: NSObject, Error {
        var desc = ""
        init(str: String) {
            desc = str
        }
        override var description: String {
            get {
                return "MyError: \(desc)"
            }
        }
       var localizedDescription: String {
            get {
                return self.description
            }
        }
    }
    
    func test_my_code() {
        let error = MyError(str: "my test string")
        let x = error as Error
        print(x.localizedDescription)
    }
    

    Calling function "test_my_code" get unexpected result: "The operation couldn’t be completed...".

    What should I do to get result "MyError: my test string" ?