Home > Mobile >  How to maintain order while fetching the JSON data?
How to maintain order while fetching the JSON data?

Time:02-14

I am building a currency converter app and I am experiencing issues with it. I am getting problems with order. I am using two internet JSON files: first with prices, second with full names. I can see that price and currency code (image here) are matching with each other, but not the full name. How can I hardcode full name to the currency code? Is it even possible? Thank you for you're answers.

Here's the code:

// JSON FILE 1
{
  "currencies": {
    "AED": "United Arab Emirates Dirham",
    "AFN": "Afghan Afghani",
    "ALL": "Albanian Lek",
    "AMD": "Armenian Dram",
    "ANG": "Dutch Guilders",
    "AOA": "Angolan Kwanza",
    "ARS": "Argentine Peso",
    "AUD": "Australian Dollar",
    "AWG": "Aruban Florin",
    "AZN": "Azerbaijani Manat",
    "BAM": "Bosnia-Herzegovina Convertible Mark",
    "BBD": "Barbadian Dollar",
    "BDT": "Bangladeshi Taka",
    "BGN": "Bulgarian Lev",
    "BHD": "Bahraini Dinar",
    "BIF": "Burundian Franc",
    "BMD": "Bermudian Dollar",
    "BND": "Bruneian Dollar",
    "BOB": "Bolivian Boliviano",
    "BRL": "Brazilian Real",
    "BSD": "Bahamian Dollar",
    "BTN": "Bhutanese Ngultrum",
    "BWP": "Botswanan Pula",
    "BZD": "Belizean Dollar",
    "CAD": "Canadian Dollar",
    "CDF": "Congolese Franc",
    "CHF": "Swiss Franc",
    "CLF": "Chilean Unit of Account UF",
    "CLP": "Chilean Peso",
    "CNH": "Chinese Yuan Offshore",
    "CNY": "Chinese Yuan",
    "COP": "Colombian Peso",
    "CUP": "Cuban Peso",
    "CVE": "Cape Verdean Escudo",
    "CZK": "Czech Republic Koruna",
    "DJF": "Djiboutian Franc",
    "DKK": "Danish Krone",
    "DOP": "Dominican Peso",
    "DZD": "Algerian Dinar",
    "EGP": "Egyptian Pound",
    "ERN": "Eritrean Nakfa",
    "ETB": "Ethiopian Birr",
    "EUR": "Euro",
    "FJD": "Fijian Dollar",
    "FKP": "Falkland Islands Pound",
    "GBP": "British Pound Sterling",
    "GEL": "Georgian Lari",
    "GHS": "Ghanaian Cedi",
    "GIP": "Gibraltar Pound",
    "GMD": "Gambian Dalasi",
    "GNF": "Guinean Franc",
    "GTQ": "Guatemalan Quetzal",
    "GYD": "Guyanaese Dollar",
    "HKD": "Hong Kong Dollar",
    "HNL": "Honduran Lempira",
    "HRK": "Croatian Kuna",
    "HTG": "Haitian Gourde",
    "HUF": "Hungarian Forint",
    "IDR": "Indonesian Rupiah",
    "ILS": "Israeli New Sheqel",
    "INR": "Indian Rupee",
    "IQD": "Iraqi Dinar",
    "IRR": "Iranian Rial",
    "ISK": "Icelandic Krona",
    "JMD": "Jamaican Dollar",
    "JOD": "Jordanian Dinar",
    "JPY": "Japanese Yen",
    "KES": "Kenyan Shilling",
    "KGS": "Kyrgystani Som",
    "KHR": "Cambodian Riel",
    "KMF": "Comorian Franc",
    "KPW": "North Korean Won",
    "KRW": "South Korean Won",
    "KWD": "Kuwaiti Dinar",
    "KYD": "Caymanian Dollar",
    "KZT": "Kazakhstani Tenge",
    "LAK": "Laotian Kip",
    "LBP": "Lebanese Pound",
    "LKR": "Sri Lankan Rupee",
    "LRD": "Liberian Dollar",
    "LSL": "Basotho Maloti",
    "LYD": "Libyan Dinar",
    "MAD": "Moroccan Dirham",
    "MDL": "Moldovan Leu",
    "MGA": "Malagasy Ariary",
    "MKD": "Macedonian Denar",
    "MMK": "Myanma Kyat",
    "MNT": "Mongolian Tugrik",
    "MOP": "Macanese Pataca",
    "MRU": "Mauritanian Ouguiya",
    "MUR": "Mauritian Rupee",
    "MVR": "Maldivian Rufiyaa",
    "MWK": "Malawian Kwacha",
    "MXN": "Mexican Peso",
    "MYR": "Malaysian Ringgit",
    "MZN": "Mozambican Metical",
    "NAD": "Namibian Dollar",
    "NGN": "Nigerian Naira",
    "NOK": "Norwegian Krone",
    "NPR": "Nepalese Rupee",
    "NZD": "New Zealand Dollar",
    "OMR": "Omani Rial",
    "PAB": "Panamanian Balboa",
    "PEN": "Peruvian Nuevo Sol",
    "PGK": "Papua New Guinean Kina",
    "PHP": "Philippine Peso",
    "PKR": "Pakistani Rupee",
    "PLN": "Polish Zloty",
    "PYG": "Paraguayan Guarani",
    "QAR": "Qatari Rial",
    "RON": "Romanian Leu",
    "RSD": "Serbian Dinar",
    "RUB": "Russian Ruble",
    "RWF": "Rwandan Franc",
    "SAR": "Saudi Arabian Riyal",
    "SCR": "Seychellois Rupee",
    "SDG": "Sudanese Pound",
    "SEK": "Swedish Krona",
    "SGD": "Singapore Dollar",
    "SHP": "Saint Helena Pound",
    "SLL": "Sierra Leonean Leone",
    "SOS": "Somali Shilling",
    "SRD": "Surinamese Dollar",
    "SYP": "Syrian Pound",
    "SZL": "Swazi Emalangeni",
    "THB": "Thai Baht",
    "TJS": "Tajikistani Somoni",
    "TMT": "Turkmenistani Manat",
    "TND": "Tunisian Dinar",
    "TOP": "Tongan Pa'anga",
    "TRY": "Turkish Lira",
    "TTD": "Trinidad and Tobago Dollar",
    "TWD": "Taiwan New Dollar",
    "TZS": "Tanzanian Shilling",
    "UAH": "Ukrainian Hryvnia",
    "UGX": "Ugandan Shilling",
    "USD": "United States Dollar",
    "UYU": "Uruguayan Peso",
    "UZS": "Uzbekistan Som",
    "VND": "Vietnamese Dong",
    "VUV": "Ni-Vanuatu Vatu",
    "WST": "Samoan Tala",
    "XAF": "CFA Franc BEAC",
    "XCD": "East Caribbean Dollar",
    "XDR": "Special Drawing Rights",
    "XOF": "CFA Franc BCEAO",
    "XPF": "CFP Franc",
    "YER": "Yemeni Rial",
    "ZAR": "South African Rand",
    "ZMW": "Zambian Kwacha"
  },
  "ms": 6
}
// JSON FILE 2
{
  "base": "USD",
  "results": {
    "AED": 3.67206,
    "AFN": 93.40685,
    "ALL": 106.27627,
    "AMD": 480.17107,
    "ANG": 1.78799,
    "AOA": 528.20073,
    "ARS": 105.9003,
    "AUD": 1.3922,
    "AWG": 1.79899,
    "AZN": 1.70213,
    "BAM": 1.7137,
    "BBD": 1.99913,
    "BDT": 84.84226,
    "BGN": 1.70849,
    "BHD": 0.37606,
    "BIF": 2011.72969,
    "BMD": 0.99908,
    "BND": 1.34108,
    "BOB": 6.87374,
    "BRL": 5.25859,
    "BSD": 1.00152,
    "BTN": 74.88828,
    "BWP": 11.59835,
    "BZD": 2.01424,
    "CAD": 1.26778,
    "CDF": 2000.85683,
    "CHF": 0.92368,
    "CLF": 0.02563,
    "CLP": 813.61766,
    "CNH": 6.36222,
    "CNY": 6.36106,
    "COP": 3931.5793,
    "CUP": 24.99125,
    "CVE": 96.37768,
    "CZK": 21.27424,
    "DJF": 177.90121,
    "DKK": 6.51045,
    "DOP": 57.34036,
    "DZD": 140.79316,
    "EGP": 15.70478,
    "ERN": 15.1307,
    "ETB": 50.15401,
    "EUR": 0.87483,
    "FJD": 2.12693,
    "FKP": 0.73865,
    "GBP": 0.73865,
    "GEL": 2.9288,
    "GHS": 6.25112,
    "GIP": 0.73865,
    "GMD": 53.0933,
    "GNF": 9046.03975,
    "GTQ": 7.68413,
    "GYD": 209.88012,
    "HKD": 7.78983,
    "HNL": 24.49709,
    "HRK": 6.62491,
    "HTG": 104.54045,
    "HUF": 308.55425,
    "IDR": 14339.61428,
    "ILS": 3.21294,
    "INR": 74.78561,
    "IQD": 1457.71626,
    "IRR": 42022.92755,
    "ISK": 124.39523,
    "JMD": 155.80686,
    "JOD": 0.70759,
    "JPY": 115.42734,
    "KES": 113.303,
    "KGS": 85.05721,
    "KHR": 4066.33034,
    "KMF": 430.64639,
    "KPW": 900.02438,
    "KRW": 1193.7614,
    "KWD": 0.302,
    "KYD": 0.82061,
    "KZT": 425.47661,
    "LAK": 11394.85755,
    "LBP": 1510.16006,
    "LKR": 203.02401,
    "LRD": 153.41882,
    "LSL": 15.36242,
    "LYD": 4.57184,
    "MAD": 9.30782,
    "MDL": 17.85335,
    "MGA": 3995.92268,
    "MKD": 53.81939,
    "MMK": 1773.0882,
    "MNT": 2856.09715,
    "MOP": 8.02612,
    "MRU": 36.38995,
    "MUR": 44.03891,
    "MVR": 15.66053,
    "MWK": 810.96593,
    "MXN": 20.49223,
    "MYR": 4.1845,
    "MZN": 63.66124,
    "NAD": 15.20043,
    "NGN": 416.64463,
    "NOK": 8.80997,
    "NPR": 119.8895,
    "NZD": 1.49518,
    "OMR": 0.38407,
    "PAB": 0.99908,
    "PEN": 3.80791,
    "PGK": 3.51972,
    "PHP": 51.26921,
    "PKR": 174.34464,
    "PLN": 3.932,
    "PYG": 6963.85809,
    "QAR": 3.63947,
    "RON": 4.32397,
    "RSD": 102.80611,
    "RUB": 74.5714,
    "RWF": 1012.01037,
    "SAR": 3.74805,
    "SCR": 14.50692,
    "SDG": 441.096,
    "SEK": 9.0993,
    "SGD": 1.34151,
    "SHP": 0.73865,
    "SLL": 11353.1241,
    "SOS": 585.55358,
    "SRD": 20.78836,
    "SYP": 2511.26803,
    "SZL": 15.2251,
    "THB": 32.70654,
    "TJS": 11.31708,
    "TMT": 3.50647,
    "TND": 2.85947,
    "TOP": 2.29205,
    "TRY": 13.54047,
    "TTD": 6.77401,
    "TWD": 27.81745,
    "TZS": 2311.33156,
    "UAH": 28.07199,
    "UGX": 3498.77016,
    "USD": 1,
    "UYU": 43.49342,
    "UZS": 10849.73741,
    "VND": 22714.81648,
    "VUV": 113.09101,
    "WST": 2.62152,
    "XAF": 573.7131,
    "XCD": 2.69908,
    "XDR": 0.71235,
    "XOF": 573.7131,
    "XPF": 104.29227,
    "YER": 249.84599,
    "ZAR": 15.23648,
    "ZMW": 18.60965
  },
  "updated": "2022-02-09 17:30:18",
  "ms": 2
} 

// Model
 import Foundation



struct CurrencyModel: Codable {
    var results: [String:Double]
}

struct CurrencyNameModel: Codable {
    var currencies: [String:String]
}

// Two ViewModels
import Foundation


class CurrencyViewModel: ObservableObject {
    
    @Published var currencyCode: [String] = []
    @Published var exchagePrice: [Double] = []
    
    init() {
        
        fetchData { (currency) in
            switch currency {
        case .success(let prices):
                DispatchQueue.main.async {
                    self.currencyCode.append(contentsOf: prices.results.keys)
                    // self.currencyCode.sorted()
                    self.exchagePrice.append(contentsOf: prices.results.values)
            }
            case .failure(let error):
                print("Error", error)
        }
    }
}
    
    

   
    
func fetchData(completion: @escaping (Result<CurrencyModel,Error>) -> ()) {
    guard let url = URL(string: "https://api.fastforex.io/fetch-all?api_key=...") else { return }
    URLSession.shared.dataTask(with: url) { data, responce, error in
        if let error = error {
            completion(.failure(error))
            return
        }
        
        guard let safeData = data else { return }
        
        do {
            let currency = try JSONDecoder().decode(CurrencyModel.self, from: safeData)
            completion(.success(currency))
        }
        catch {
            completion(.failure(error))
        }
    }
    .resume()
    
    }
}

////////

import Foundation

class CurrencyViewModelNew: ObservableObject {
    

    @Published var currencyName: [String] = []
    
init() {
    fetchNewData { (name) in
        switch name {
    case .success(let prices):
            DispatchQueue.main.async {

                self.currencyName.append(contentsOf: prices.currencies.values)
                
            }
        case .failure(let error):
            print("Error", error)
            
            }
        }
    }
    
    func fetchNewData(completion: @escaping (Result<CurrencyNameModel,Error>) -> ()) {
        guard let url = URL(string: "https://api.fastforex.io/currencies?api_key=...") else { return }
        URLSession.shared.dataTask(with: url) { data, responce, error in
            if let error = error {
                completion(.failure(error))
                return
            }
            
            guard let safeData = data else { return }
            
            do {
                let currency = try JSONDecoder().decode(CurrencyNameModel.self, from: safeData)
                completion(.success(currency))
            }
            catch {
                completion(.failure(error))
            }
        }
        .resume()
        
        }
    
}

// View just in case
import SwiftUI


struct CurrencyView: View {
    @ObservedObject var api1 = CurrencyViewModel()
    @ObservedObject var api2 = CurrencyViewModelNew()
    
    @State private var pickerSelection1 = 0
    @State private var pickerSelection2 = 0
    

    
    var body: some View {
        Picker("", selection: $pickerSelection1) {
            ForEach(0..<self.api1.currencyCode.count) {
                let currency = api1.currencyCode[$0]
        Text(currency)
            }
        }
        .id(UUID())
       
        Picker("", selection: $pickerSelection1) {
            ForEach(0..<self.api2.currencyName.count) {
                let name = api2.currencyName[$0]
        Text(name)
            }
        }
        .id(UUID())
        
        Picker("", selection: $pickerSelection1) {
            ForEach(0..<self.api1.exchagePrice.count) {
                let price = "\(api1.exchagePrice[$0])"
                Text(price)
            }
        }
        .id(UUID())
    }
}

struct CurrencyView_Previews: PreviewProvider {
    static var previews: some View {
        CurrencyView()
    }
}


CodePudding user response:

Perhaps it would make more sense to create a Currency model for each currency.

struct Currency {
    let name: String
    let symbol: String
    let value_USD: Double
}

And construct a function to parse the two dictionaries (of values and names) to map an array of currencies.

// Our parsed JSON data
let currencyValues: [String: Double] = [
    "AED": 3.67206,
    "AFN": 93.40685,
    "ALL": 106.27627
]
let currencyNames: [String: String] = [
    "AED": "United Arab Emirates Dirham",
    "AFN": "Afghan Afghani",
    "ALL": "Albanian Lek"
]

// A simple function to parse them
func getCurrencies() -> [Currency] {
    var currencies: [Currency] = []
    
    for entry in currencyValues {
        let symbol = entry.key
        let usdValue = entry.value
        
        if let name = currencyNames[symbol] {
            let c = Currency(name: name, symbol: symbol, value_USD: usdValue)
            currencies.append(c)
        }
    }
    return currencies
}

let currencies = getCurrencies()
for currency in currencies {
    print(currency.symbol, currency.name, currency.value_USD)
}

// AFN Afghan Afghani 93.40685
// AED United Arab Emirates Dirham 3.67206
// ALL Albanian Lek 106.27627

CodePudding user response:

The best way forward IMO is to create a custom type that contains the values from both json collections and then use this type throughout your app.

struct Currency {
    let currencyCode: String
    let name: String
    var price: Double
}

One option here is to make the type Codable and decode it using a custom init(from:) and while this is a good approach here I will leave the decoding as it is and create the Currency objects from CurrencyNameModel instead,

let currencies = values.currencies.map { Currency(currencyCode: $0.key, name: $0.value, price: 0) }

then update it with the prices from CurrencyModel

for (index, value) in currencies.enumerated() {
    if let model = values.results.first(where: { $0.key == value.currencyCode }) {
        currencies[index].price = model.value
    }
}

This would all be done in the CurrencyViewModel so it would be changed to

class CurrencyViewModel: ObservableObject {
    @Published var currencies: [Currency] = []

    init() {
        fetchNewData { (currency) in
            switch currency {
            case .success(let names):
                self.currencies = names.currencies.map {
                    Currency(currencyCode: $0.key, name: $0.value, price: 0)
                }
                fetchData { result in
                    switch result {
                    case .success(let prices):
                        for (index, value) in currencies.enumerated() {
                            if let price = prices.results.first(where: { $0.key == value.currencyCode }) {
                                currencies[index].price = price.value
                            }
                        }
                    case .failure(let error):
                        print(error)
                    }
                }
            case .failure(let error):
                print("Error", error)
            }
        }
    }
}
  • Related