Printing DecodingError details on decode failed in Swift
Asked Answered
P

3

21

I'm starting to rewrite an application and I want to use Swift 4 Codable protocol to automatically convert json string to Objects and Structs.

Sometimes, specially at the beginning of coding, I encountered decoding problems, so I want to print these errors (whithout using always the debugger), in case some beans are not decoded correctly.

The problem is this:

enter image description here

As you can see, in the debugger, on "decodingError" object there is both:

  • the key that has got the problem (NominativoModel.denNome)
  • the error encountered (Expected to encode Array bla bla bla...).

My problem is that the only properties of that element, in the code, are errorDescription, failureReason, etc, that are ALL nil.

How can I print the values that are correctly displayed in the debugger?

Pelota answered 27/9, 2018 at 14:33 Comment(0)
E
38

DecodingError is an enum. In your case you have to catch the typeMismatch case and print the type and the context.

catch let DecodingError.typeMismatch(type, context)  {
   print("Type '\(type)' mismatch:", context.debugDescription)
   print("codingPath:", context.codingPath)
}
Exultant answered 27/9, 2018 at 14:52 Comment(5)
That's It! Thank you! These Swift Enums are very powerful but so simple to use.Pelota
Just what I was looking for! ThanksDogvane
@user10447655 This depends on the context.Exultant
I want to throw the same error that I would be catching. The catching would just be a place to log.Cooler
context.debugDescription never writes any error.Unwisdom
E
35
catch let error as DecodingError {
   switch error {
            case .typeMismatch(let key, let value):
              print("error \(key), value \(value) and ERROR: \(error.localizedDescription)")
            case .valueNotFound(let key, let value):
              print("error \(key), value \(value) and ERROR: \(error.localizedDescription)")
            case .keyNotFound(let key, let value):
              print("error \(key), value \(value) and ERROR: \(error.localizedDescription)")
            case .dataCorrupted(let key):
              print("error \(key), and ERROR: \(error.localizedDescription)")
            default:
              print("ERROR: \(error.localizedDescription)")
            }
   }
Entrench answered 6/10, 2020 at 17:42 Comment(0)
M
0

Fancy over the top pretty print that spills everything you wanted to know about the error:

do {
  return try decoder.decode(...)
} catch let error as DecodingError {
  print(error.prettyDescription)
}
private extension DecodingError {
    var prettyDescription: String {
        switch self {
        case let .typeMismatch(type, context):
            "DecodingError.typeMismatch \(type), value \(context.prettyDescription) @ ERROR: \(localizedDescription)"
        case let .valueNotFound(type, context):
            "DecodingError.valueNotFound \(type), value \(context.prettyDescription) @ ERROR: \(localizedDescription)"
        case let .keyNotFound(key, context):
            "DecodingError.keyNotFound \(key), value \(context.prettyDescription) @ ERROR: \(localizedDescription)"
        case let .dataCorrupted(context):
            "DecodingError.dataCorrupted \(context.prettyDescription), @ ERROR: \(localizedDescription)"
        default:
            "DecodingError: \(localizedDescription)"
        }
    }
}

private extension DecodingError.Context {
    var prettyDescription: String {
        var result = ""
        if !codingPath.isEmpty {
            result.append(codingPath.map(\.stringValue).joined(separator: "."))
            result.append(": ")
        }
        result.append(debugDescription)
        if
            let nsError = underlyingError as? NSError,
            let description = nsError.userInfo["NSDebugDescription"] as? String
        {
            result.append(description)
        }
        return result
    }
}
Muraida answered 1/12, 2023 at 16:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.