I'm trying to decode the JSON response for all tags from the Pinboard API. I have a simple model I'd like to decode into:
struct Tag: Coddle, Hashable {
let name: String
let count: Int
}
The problem is that the JSON response I get is entirely dynamic, like this:
{
"tag_name_1": 5,
"tag_name_2": 5,
"tag_name_3": 5,
}
So decoding into my model using JSONDecoder.decode([Tag].self, data)
always fails.
CodePudding user response:
Your JSON can be decoded into a dictionary of type [String: Int]
.
If you enter key and value of each entry of the dictionary into a Tag
object, you can then sort the array of tags by name
. Or you can sort the dictionary keys first, both work.
Catch: it will work only if the order of the JSON is also the order of the keys. It will NOT follow the order if the JSON arrives like this, for example:
{
"tag_name_3": 5,
"tag_name_2": 5,
"tag_name_1": 5,
}
Here's the code (with two options):
// First way:
// 1) Decode the dictionary
// 2) Sort the dictionary keys
// 3) Iterate, creating a new Tag and appending it to the array
private func decode1() {
let json = "{ \"tag_name_1\": 5, \"tag_name_2\": 5, \"tag_name_3\": 5}"
let data = json.data(using: .utf8)
do {
// Decode into a dictionary
let decoded = try JSONDecoder().decode([String: Int].self, from: data!)
print(decoded.sorted { $0.key < $1.key })
var tags = [Tag]()
// Iterate over a sorted array of keys
decoded.compactMap { $0.key }.sorted().forEach {
// Create the Tag
tags.append(Tag(name: $0, count: decoded[$0] ?? 0))
}
print(tags)
} catch {
print("Oops: something went wrong while decoding, \(error.localizedDescription)")
}
}
// Second way:
// 1) Decode the dictionary
// 2) Create the Tag objects
// 3) Sort the array by Tag.name
private func decode2() {
let json = "{ \"tag_name_1\": 5, \"tag_name_2\": 5, \"tag_name_3\": 5}"
let data = json.data(using: .utf8)
do {
// Decode into a dictionary
let decoded = try JSONDecoder().decode([String: Int].self, from: data!)
print(decoded.sorted { $0.key < $1.key })
var tags = [Tag]()
// Iterate over the dictionary entries
decoded.forEach {
// Create the Tag
tags.append(Tag(name: $0.key, count: $0.value))
}
// Sort the array by name
tags = tags.sorted { $0.name < $1.name }
print(tags)
} catch {
print("Oops: something went wrong while decoding, \(error.localizedDescription)")
}
}