-1

I am trying to decode some JSON from an API that looks like this (foo is short for a list of properties):

{"page":1,"total_results":10000,"total_pages":500,"results":[{"foo":"bar"},{"foo":"bar2"},{"foo":"bar3"}]}

The struct recommended by quicktype.io which looks correct to me too is:

struct ObjectsReturned: Codable {
    let page, totalResults, totalPages: Int
    let results: [Result]

    enum CodingKeys: String, CodingKey {
        case page
        case totalResults = "total_results"
        case totalPages = "total_pages"
        case results
    }
}

// MARK: - Result
struct Result: Codable {
    let foo: String
}

However, when I try to decode, although it is able to handle page, it throws an error on total_results as follows:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [_DictionaryCodingKey(stringValue: "total_results", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found a number instead.", underlyingError: nil))

What could be the reason for this error and how can I fix it?

Thanks for any suggestions.

Note:

Decoding is via:

do {
                            let mything = try JSONDecoder().decode([String:ObjectReturned].self, from: data)
                        } catch {
                            print(error)
                        }
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
user6631314
  • 1,751
  • 1
  • 13
  • 44

2 Answers2

1

You are trying to decode the wrong type. Your root object is a single ObjectsReturned instance and not a [String:ObjectsReturned].

let mything = try JSONDecoder().decode(ObjectsReturned.self, from: json2)
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
1

The error itself is very clear, it says you're trying to decode a Dictionary but the JSONDecoder couldn't find one. You probably copied this code from somewhere else and that's probably the reason for making this mistake. You should be able to figure out the model by just looking at it. Here you can see that there is no key at the beginning whose value is the expected ObjectReturned. If the JSON has been:

{"someStringKey":{"page":1,"total_results":10000,"total_pages":500,"results":[{"foo":"bar"},{"foo":"bar2"},{"foo":"bar3"}]}}

your decoding should have worked. Instead in your case, the JSON doesn't have the leading key as in the above example "someStringKey" so you just need:

do {
    let mything = try JSONDecoder().decode(ObjectsReturned.self, from: data)
    print(mything)
} catch {
    print(error)
}

It's always best to paste your JSON at Quicktype and generate the struct model from there for decoding. Hope this helps with any JSON decoding related difficulties.

Frankenstein
  • 15,732
  • 4
  • 22
  • 47
  • Thanks! Upvoted your in depth answer for the explanation as I'd already accepted other one. Quick type did have the correct JSON decoder code. Yes, I must have copied code for parsing a different api in the format you suggest and changed the object name without changing the rest of it. – user6631314 Jul 28 '20 at 14:41
  • You're welcome. It was a common mistake due to lack of attention. Anyways Happy coding :) – Frankenstein Jul 28 '20 at 14:49
  • Quicktype is great but occasionally it generates a lot of auxiliary classes. Do you try to improve on it when that happens? https://stackoverflow.com/questions/63138535/eliminating-quicktype-accessory-methods-when-parsng-json-to-swift – user6631314 Jul 28 '20 at 16:20