smukamuka
smukamuka

Reputation: 1537

Printing DecodingError details on decode failed in Swift

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:

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?

Upvotes: 21

Views: 13995

Answers (3)

Aviel Gross
Aviel Gross

Reputation: 9975

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
    }
}

Upvotes: 0

Taras
Taras

Reputation: 1899

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)")
            }
   }

Upvotes: 35

vadian
vadian

Reputation: 285072

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)
}

Upvotes: 38

Related Questions