I am making an API call which returns the following JSON structure (price info about various cryptocurrencies):
{
"bitcoin": {
"gbp": 34532
},
"ethereum": {
"gbp": 2789.08
}
}
The struct I am using to decode this JSON looks like this:
struct Coin: Codable {
let gbp: Double
enum CodingKeys: String, CodingKey {
case gbp
}
}
The JSON is not being decoded because the parent of each JSON element returned is the name of a cryptocurrency, but this will change depending on what call is made. As the name always changes, I am not sure how to create a variable in the struct to map each parent. E.g. for this example I could make a struct like this:
struct AllCoins: Codable {
let bitcoin, ethereum: Coin
}
This will decode this specific example, but if I fetch other coins it will not work because the String names are different, so they will not match up. I am sure I am missing something simple here, but does anyone know how I can go about solving this issue?
CodePudding user response:
If the name can be any arbitrary string, you want to decode a [String: Coin] dictionary. As long as Coin is Codable, [String: Coin] is also Codable.
CodePudding user response:
I regard the effort to decode the JSON with Codable higher than with traditional JSONSerialization. As long as the structure is always
{"<name>":
{"<base>": <value>}
}
you can decode any currency and any base with this code, the result is an array of Coin
let jsonString = """
{
"bitcoin": {
"gbp": 34532
},
"ethereum": {
"gbp": 2789.08
}
}
"""
struct Coin {
let name : String
let base : String
let value : Double
}
var coins = [Coin]()
do {
let result = try JSONSerialization.jsonObject(with: Data(jsonString.utf8)) as! [String:[String:Double]]
coins = result.compactMap{ key, rate in
guard let base = rate.keys.first else { return nil }
return Coin(name: key, base: base, value: rate[base]!)
}
print(coins)
} catch {
print(error)
}
