I am trying to parse some JSON response coming from CoinmarketCap using the JSONDecoder()
in Swift 4. But the problem is that the response from json is changing according to user input. e.g if user wants the price in eur, the output is following:
[
{
"price_eur": "9022.9695444"
}
]
but if user wants the price in gbp:
[
{
"price_gbp": "7906.8032145"
}
]
So the question is how should I make the struct that inherits from Decodable
if the variable(json key) name is changing?
You can decode the dynamic key by creating a custom init(from:)
method for your struct, then using two set of coding keys, an enum
containing all keys that are known at compile time and another struct
that you initialize using the dynamic keys that are generated using user input (contain the name of the currency).
In your custom init(from:)
method you just need to decode each property using their respective keys.
let chosenCurrency = "gbp"
struct CurrencyResponse: Decodable {
let name:String
let symbol:String
let price:String
private static var priceKey:String {
return "price_\(chosenCurrency)"
}
private enum SimpleCodingKeys: String, CodingKey {
case name, symbol
}
private struct PriceCodingKey : CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
return nil
}
}
init(from decoder:Decoder) throws {
let values = try decoder.container(keyedBy: SimpleCodingKeys.self)
name = try values.decode(String.self, forKey: .name)
symbol = try values.decode(String.self, forKey: .symbol)
let priceValue = try decoder.container(keyedBy: PriceCodingKey.self)
price = try priceValue.decode(String.self, forKey: PriceCodingKey(stringValue:CurrencyResponse.priceKey)!)
}
}
do {
let cryptoCurrencies = try JSONDecoder().decode([CurrencyResponse].self, from: priceJSON.data(using: .utf8)!)
} catch {
print(error)
}
Test JSON:
let priceJSON = """
[
{
"id": "bitcoin",
"name": "Bitcoin",
"symbol": "BTC",
"rank": "1",
"price_\(chosenCurrency)": "573.137",
"price_btc": "1.0",
"24h_volume_\(chosenCurrency)": "72855700.0",
"market_cap_\(chosenCurrency)": "9080883500.0",
"available_supply": "15844176.0",
"total_supply": "15844176.0",
"percent_change_1h": "0.04",
"percent_change_24h": "-0.3",
"percent_change_7d": "-0.57",
"last_updated": "1472762067"
},
{
"id": "ethereum",
"name": "Ethereum",
"symbol": "ETH",
"rank": "2",
"price_\(chosenCurrency)": "12.1844",
"price_btc": "0.021262",
"24h_volume_\(chosenCurrency)": "24085900.0",
"market_cap_\(chosenCurrency)": "1018098455.0",
"available_supply": "83557537.0",
"total_supply": "83557537.0",
"percent_change_1h": "-0.58",
"percent_change_24h": "6.34",
"percent_change_7d": "8.59",
"last_updated": "1472762062"
}
]
"""