I am very new to Swift coming from Obj C background. I am struggling to access a couple of key value pairs in a dictionary that comes from some JSON returned from an API endpoint. I can get as far as "data" but not sure how to get access to the arrays below that key. Specifically I am trying to return values for "id" and "price" as follows:
id = 1;
price = "20160.67609688202"
I would appreciate any help you might offer. Thank you.
Swift:
@IBAction func buttonAction(_ sender: Any) {
// Create the URL
let query = txt_Symbol.text
let api = "https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?CMC_PRO_API_KEY=myKey&symbol="
let endpoint = query!
let url = URL(string: api endpoint)
guard let requestUrl = url else { fatalError() }
// Create URL Request
var request = URLRequest(url: requestUrl)
// Specify HTTP Method to use
request.httpMethod = "GET"
// Send HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check if Error took place
if let error = error {
print("Error took place \(error)")
return
}
// Read HTTP Response Status code
if let response = response as? HTTPURLResponse {
print("Response HTTP Status code: \(response.statusCode)")
}
// Convert HTTP Response Data to a simple String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
do {
if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
// Print out entire dictionary
print("convertedJsonIntoDict:")
print(convertedJsonIntoDict)
// UI API called on a background thread
// Call this on the main thread
DispatchQueue.main.async {
//Do UI Code here.
self.txtarea_JSON.text = convertedJsonIntoDict.description
// Get a value by key
let coinData = convertedJsonIntoDict["data"]
print(coinData ?? "coin could not be read")
// how do I access these key value pairs?
// id = 1;
// price = "20160.67609688202"
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
}
task.resume()
}
JSON:
{
data = {
BTC = {
"circulating_supply" = 19138912;
"cmc_rank" = 1;
"date_added" = "2013-04-28T00:00:00.000Z";
id = 1;
"is_active" = 1;
"is_fiat" = 0;
"last_updated" = "2022-09-02T03:39:00.000Z";
"max_supply" = 21000000;
name = Bitcoin;
"num_market_pairs" = 9718;
platform = "<null>";
quote = {
USD = {
"fully_diluted_market_cap" = "423374198034.52";
"last_updated" = "2022-09-02T03:39:00.000Z";
"market_cap" = "385853405678.7285";
"market_cap_dominance" = "39.0616";
"percent_change_1h" = "0.83296442";
"percent_change_24h" = "0.16774456";
"percent_change_30d" = "-11.73989491";
"percent_change_60d" = "5.58985077";
"percent_change_7d" = "-6.59123025";
"percent_change_90d" = "-31.87091684";
price = "20160.67609688202";
tvl = "<null>";
"volume_24h" = "29753736862.94145";
"volume_change_24h" = "-7.2446";
};
};
"self_reported_circulating_supply" = "<null>";
"self_reported_market_cap" = "<null>";
slug = bitcoin;
symbol = BTC;
tags = (
mineable,
pow,
"sha-256",
"store-of-value",
"state-channel",
"coinbase-ventures-portfolio",
"three-arrows-capital-portfolio",
"polychain-capital-portfolio",
"binance-labs-portfolio",
"blockchain-capital-portfolio",
"boostvc-portfolio",
"cms-holdings-portfolio",
"dcg-portfolio",
"dragonfly-capital-portfolio",
"electric-capital-portfolio",
"fabric-ventures-portfolio",
"framework-ventures-portfolio",
"galaxy-digital-portfolio",
"huobi-capital-portfolio",
"alameda-research-portfolio",
"a16z-portfolio",
"1confirmation-portfolio",
"winklevoss-capital-portfolio",
"usv-portfolio",
"placeholder-ventures-portfolio",
"pantera-capital-portfolio",
"multicoin-capital-portfolio",
"paradigm-portfolio"
);
"total_supply" = 19138912;
"tvl_ratio" = "<null>";
};
};
status = {
"credit_count" = 1;
elapsed = 35;
"error_code" = 0;
"error_message" = "<null>";
notice = "<null>";
timestamp = "2022-09-02T03:41:38.218Z";
};
}
CodePudding user response:
From the JSON
response you showed in your question here is the way to get values from it:
do {
guard let response = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
print("JSONSerialization Not possible")
return
}
guard let data = response["data"] as? [String: Any] else { return }
guard let btc = data["BTC"] as? [String: Any] else { return }
guard let quote = btc["quote"] as? [String: Any], let usd = quote["USD"] as? [String: Any] else { return }
let id = btc["id"] as? Int ?? 0
let price = usd["price"] as? String ?? ""
print(id) //1
print(price) //20160.67609688202
} catch let error {
print(error.localizedDescription)
}
CodePudding user response:
You could decode the api response into a set of models (struct) instead of a dictionary.
Here is an example code that shows how to decode the api response and use it. (you will need to adjust the models according to the server documentations)
Once you have the data decoded into the models, it is far easier to deal with than a dictionary of nested (key,value) pairs.
let formatter: DateFormatter = {
let frmt = DateFormatter()
frmt.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
return frmt
}()
if let data = data {
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let decoded = try decoder.decode(APIResponse.self, from: data)
// print("\n---> decoded: \n \(decoded)")
if let coinData = decoded.data.first?.value {
print("\n---> coinData: \n \(coinData)")
print("\n---> coinData name: \n \(coinData.name)")
print("\n---> coinData quote: \n \(coinData.quote)")
print("\n---> coinData quote usd: \n \(coinData.quote.usd)")
}
} catch {
print("==> decoding error: \(error)")
}
}
Where the models are declared as follows:
struct APIResponse: Codable {
let data: [String : CoinData]
let status: Status
}
struct CoinData: Identifiable, Codable {
let id: Int
let name, symbol, slug: String
let isActive, isFiat, circulatingSupply, totalSupply: Int
let maxSupply: Int
let dateAdded: Date
let numMarketPairs, cmcRank: Int
let lastUpdated: Date
let tags: [String]
let platform, selfReportedCirculatingSupply, selfReportedMarketCap: String?
let quote: Quote
enum CodingKeys: String, CodingKey {
case id, name, symbol, slug
case isActive = "is_active"
case isFiat = "is_fiat"
case circulatingSupply = "circulating_supply"
case totalSupply = "total_supply"
case maxSupply = "max_supply"
case dateAdded = "date_added"
case numMarketPairs = "num_market_pairs"
case cmcRank = "cmc_rank"
case lastUpdated = "last_updated"
case tags, platform
case selfReportedCirculatingSupply = "self_reported_circulating_supply"
case selfReportedMarketCap = "self_reported_market_cap"
case quote
}
}
struct Quote: Codable {
let usd: Usd
enum CodingKeys: String, CodingKey {
case usd = "USD"
}
}
struct Usd: Codable {
let price, volume24H, volumeChange24H, percentChange1H: Double
let percentChange24H, percentChange7D, percentChange30D, marketCap: Double
let marketCapDominance: Int
let fullyDilutedMarketCap: Double
let lastUpdated: Date
enum CodingKeys: String, CodingKey {
case price
case volume24H = "volume_24h"
case volumeChange24H = "volume_change_24h"
case percentChange1H = "percent_change_1h"
case percentChange24H = "percent_change_24h"
case percentChange7D = "percent_change_7d"
case percentChange30D = "percent_change_30d"
case marketCap = "market_cap"
case marketCapDominance = "market_cap_dominance"
case fullyDilutedMarketCap = "fully_diluted_market_cap"
case lastUpdated = "last_updated"
}
}
struct Status: Codable {
let timestamp: Date
let errorCode: Int
let errorMessage: String
let elapsed, creditCount: Int
enum CodingKeys: String, CodingKey {
case timestamp
case errorCode = "error_code"
case errorMessage = "error_message"
case elapsed
case creditCount = "credit_count"
}
}