Home > other >  Swift Accessing array values within dictionary
Swift Accessing array values within dictionary

Time:09-02

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"
    }
}
  • Related