Home > Blockchain >  Try to parse JSON from restcountries v.3.1 with SWIFT
Try to parse JSON from restcountries v.3.1 with SWIFT

Time:02-01

I'm new at Swift and programming at all.And sorry for my English, it's not my native language :)

I'm try to complete course 100 days of Swift, and for now my challenge make app with countries and their detail information, like population, capital, name etc. I'm trying to parse Json data from this link https://restcountries.com/v3.1/all. For now I can parse name and population but I stuck at capital. This is part of Json:

[
  {
    "name": {
      "common": "Brunei",
      "official": "Nation of Brunei, Abode of Peace",
      "nativeName": {
        "msa": {
          "official": "Nation of Brunei, Abode Damai",
          "common": "Negara Brunei Darussalam"
        }
      }
    },
    "tld": [
      ".bn"
    ],
    "cca2": "BN",
    "ccn3": "096",
    "cca3": "BRN",
    "cioc": "BRU",
    "independent": true,
    "status": "officially-assigned",
    "unMember": true,
    "currencies": {
      "BND": {
        "name": "Brunei dollar",
        "symbol": "$"
      },
      "SGD": {
        "name": "Singapore dollar",
        "symbol": "$"
      }
    },
    "idd": {
      "root": " 6",
      "suffixes": [
        "73"
      ]
    },
    "capital": [
      "Bandar Seri Begawan"
    ],
    "altSpellings": [
      "BN",
      "Brunei Darussalam",
      "Nation of Brunei",
      "the Abode of Peace"
    ],
    "region": "Asia",
    "subregion": "South-Eastern Asia",
    "languages": {
      "msa": "Malay"
    }

This struct what I did

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

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

This code of my viewController with parse method:

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
            }
           
        }
        
        // Do any additional setup after loading the view.
    }
    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.countryPopulation = countries[indexPath.row].population
//            vc.capitalName = countries[indexPath.row].capital[0]
            vc.imageName = countries[indexPath.row].cca2.lowercased()
            present(vc, animated: true)
        }
        
    }
    
    func parse(json: Data) {
        let decoder = JSONDecoder()

        if let jsonCountries = try? decoder.decode([Country].self, from: json) {
            countries = jsonCountries
            tableView.reloadData()
        }
        
    }
//    func showError() {
//        let ac = UIAlertController(title: "Loading error", message: "There was a problem loading the feed; please check your connection and try again.", preferredStyle: .alert)
//        ac.addAction(UIAlertAction(title: "OK", style: .default))
//        present(ac, animated: true)
//    }
}

I understand something wrong with my struct, because capital is an array in Json, how I can declare let capital properly?

CodePudding user response:

First of all when debugging never use try? because it hides the error. Use a proper way to catch the error.

If u run your function with proper error handling, it will show you the error message as follows.

func parse(json: Data) {
   let decoder = JSONDecoder()
    do {
       let jsonCountries = try decoder.decode([Country].self, from: json)
        countries = jsonCountries
     }
    catch let error {
        print(error)
     }
}

Error

keyNotFound(CodingKeys(stringValue: "capital", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 24", intValue: 24)], debugDescription: "No value associated with key CodingKeys(stringValue: \"capital\", intValue: nil) (\"capital\").", underlyingError: nil))

Simply in your json 24th element does not have a value for the capital.

So change the line let capital: [String] to let capital: [String]? .

Happy coding !

  •  Tags:  
  • Related