skip to Main Content

I start learning swift with Paul Hudson’s "100 Days of Swift" and I need your advices.
I’m trying making app with country’s info (capital, language, currencies etc.) and stuck with trying represent result of my JSON parsing in tableView.
This is my struct for parsing country’s info from https://restcountries.com/v3.1/all

struct Country: Codable {
    let name: Name
    let cca2: String
    let capital: [String]?
    let population: Int
    let currencies: [String: Currency]?
}

struct Name: Codable {
    let common: String
    let official: String
}

struct Currency: Codable {
        let name: String?
        let symbol: String?
    }

I have problems with currencies. I don’t understand how represent them properly in tableView. This is code of my ViewController:

import UIKit

class ViewController: UITableViewController {

    var countries = [Country] ()
    override func viewDidLoad() {
        super.viewDidLoad()
        let urlString = "https://restcountries.com/v3.1/all"
        if let url = URL(string: urlString) {
        if let data = try? Data(contentsOf: url) {
                parse(json: data)
                return
            }
           
        }
        
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        countries.count
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Country", for: indexPath)
        let country = countries[indexPath.row]
        cell.textLabel?.text = country.name.common
        cell.imageView?.image = UIImage(named: country.cca2.lowercased())

        
        return cell
    }
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if let vc = storyboard?.instantiateViewController(withIdentifier: "Detail") as? DetailViewController {
            vc.country = countries[indexPath.row]
            present(vc, animated: true)
        }
        
    }
    
    func parse(json: Data) {
       let decoder = JSONDecoder()
        do {
           let jsonCountries = try decoder.decode([Country].self, from: json)
            countries = jsonCountries
         }
        catch let error {
            print(error)
         }
    }
}

And this is code of my DetailViewController:

import UIKit

class DetailViewController: UITableViewController {
    var country: Country!
    let flag = "Flag"
    let general = "General"
    let currency = "Currency"
    var currencyName = ""
    var currencySymbol = ""
    lazy var sectionTitles = [flag, general, currency]
    lazy var currencies = country.currencies?.values
    
    override func viewDidLoad() {
        super.viewDidLoad()
        title = country.name.common
        getCurrencyName()
       
        }
       
    override func numberOfSections(in tableView: UITableView) -> Int {
        return sectionTitles.count
    }
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sectionTitles[section]
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch sectionTitles[section] {
        case flag:
            return 1
        case general:
            return 4
        case currency:
//            How make to return proper number's of rows??
            return 2
        default:
            return 0
        }
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        switch sectionTitles[indexPath.section] {
        case flag:
        let cell = tableView.dequeueReusableCell(withIdentifier: "Flag", for: indexPath)
            if let cell = cell as? FlagCell {
                cell.flagImageView.image = UIImage(named: country.cca2.lowercased())
            }
            return cell
            
        case general:
            let cell = tableView.dequeueReusableCell(withIdentifier: "Text", for: indexPath)
            cell.textLabel?.numberOfLines = 0
            switch indexPath.row {
            case 0:
                cell.textLabel?.text = "Common country name: (country.name.common)"
            case 1:
                cell.textLabel?.text = "Official country name: (country.name.official)"
            case 2:
                cell.textLabel?.text = "Capital: (country.capital?[0] ?? "Unknown")"
            case 3:
                cell.textLabel?.text = "Population: (country.population) people"
            default:
                return cell
            }
            return cell
            
            case currency:
            let cell = tableView.dequeueReusableCell(withIdentifier: "Text", for: indexPath)
            cell.textLabel?.numberOfLines = 0
            switch indexPath.row {
            case 0:
//          How to represent each currency of country?
                cell.textLabel?.text = "Currency name: (currencyName)"
            case 1:
                cell.textLabel?.text = "Currency symbol: (currencySymbol)"
           
            default:
                return cell
            }
            return cell
        default:
            break
        }
        return UITableViewCell ()
    }
    func getCurrencyName () {
        for currency in currencies! {
            currencyName = currency.name ?? ""
            currencySymbol = currency.symbol ?? ""
        }
       
    }
}

For now I understand how to represent one currency of each country, but how I can represent all currencies of each country in different rows?
Sorry for my English it’s not my native language 🙂

2

Answers


  1. You can access the number of currencies for each country with this, and use it in the numberOfRowsInSection method to return enough number of rows for currencies:

    country.currencies.count
    

    The rest is filling the cells in the cellForRowAt method by using the indexPath’s section and row values. You should iterate over the currencies dictionary of the selected country, and display each key and value pair in the dictionary in a row.

    You can do the iteration like so:

    for (key, value) in dict {
        // Use key and value here
    }
    
    Login or Signup to reply.
  2. I would suggest getting a sorted list of the currencies. E.g., for a given Country:

    let currencies = country.currencies?.sorted { $0.0 < $1.0 }
    

    To get the count:

    let count = currencies?.count ?? 0
    

    To get the details for a particular row, it would be:

    if let (code, currency) = currencies?[indexPath.row] {
        let currencyCode = code
        let currencyName = currency.name
        let currencySymbol = currency.symbol
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search