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)
}
}
}
}