I have prepared a simple test Playground at Github to demo my problem:
My Swift code:
struct TopResponse: Codable {
let results: [Top]
}
struct Top: Codable {
let uid: Int
let elo: Int
let given: String
let photo: String?
let motto: String?
let avg_score: String?
let avg_time: String?
}
let url = URL(string: "https://slova.de/ws/top")!
let task = URLSession.shared.dataTask(with: url) {
data, response, error in
let decoder = JSONDecoder()
guard let data2 = data,
let tops = try? decoder.decode(TopResponse.self, from:
data2) else { return }
print(tops.results[4].given)
}
task.resume()
fails to parse the fetched JSON string and does not print anything.
What could be the problem here please?
try?
That's the main culprit.
Why? You are ignoring the error thrown by the decode(_:from:)
. You are ignoring the error that could give you the exact reason or at least a hint on why it failed. Instead, write a proper do { try ... } catch { ... }
.
So:
guard let data2 = data,
let tops = try? decoder.decode(TopResponse.self, from:
data2) else { return }
print(tops.results[4].given)
=>
guard let data2 = data else { return }
do {
let tops = try decoder.decode(TopResponse.self, from: data2)
print(tops.results[4].given)
} catch {
print("Got error while parsing: \(error)")
print("With response: \(String(data: data2, encoding: .utf8))") //Just in case because I've seen plenty of code where expected JSON wasn't the one received: it was an error, doc changed, etc...
}
Output for the first print:
$>Got error while parsing: keyNotFound(CodingKeys(stringValue: "results", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"results\", intValue: nil) (\"results\").", underlyingError: nil))
Fix:
struct TopResponse: Codable {
let results: [Top]
enum CodingKeys: String, CodingKey {
case results = "data"
}
}
Or rename results
with data
.
Then, next error:
$>Got error while parsing: typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "avg_score", intValue: nil)], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil))
Extract from JSON:
"avg_score": 20.4
It's not a String
(the value it's not between double quotes), that's a Double
.
Fix:
let avg_score: String?
=>
let avg_score: Double?