Search code examples
jsonswiftcodable

How do i decode an array of dictioniaries using codable


I am trying to call an API that has an array of dictionaries: I Got the error below and not sure how I can fix. This is my struct model

struct Countries : Codable {
    var countries : [Country]
}

struct Country : Codable {
    var Country : String
    var NewConfirmed : Int
    var TotalConfirmed : Int
    var NewDeaths : Int
    var TotalDeaths : Int
    var NewRecovered : Int
    var TotalRecovered : Int
    var CountryCode : String
}

This is my networking code :

 class Networking {
    func response (url: String  , completion: @escaping (Countries) -> ()) {
        guard let url = URL(string: url) else {return}
        URLSession.shared.dataTask(with: url, completionHandler: { (data , response , error ) in
            self.urlCompletionHandler(data: data, response: response, error: error, completion: completion)
            }).resume()
    }

    func urlCompletionHandler (data: Data?  , response : URLResponse? , error : Error? , completion: (Countries) -> ()) {
        guard let data = data else {return}
        do {
            let jsondecoder = JSONDecoder()
            let countries = try jsondecoder.decode(Countries.self, from: data)
            completion(countries)
        } catch {
            print("Error \(error)")
        }
    }
}

And this is my call in the controller :

  func response () {
                newtorkhanler.response(url: UrlPathSingleTon.urlsingleton.shared()) { (countried : (Countries)) in
                    self.countrizs = countried.countries
                    DispatchQueue.main.async {
                        self.tableview.reloadData()
                    }
                }

I want to populate an array of Country that I made it as an array variable inside Countries struct. My plan is to decode the Countries and use its array variable of Country that I named countries and set to the countrizs array of Country inside response function. I get this error that is specific to the countries variable inside the Countries struct :

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

And this is the API json format: the array JSON data is in the attached pic:

json data pic

{
    "Countries": [
         {
            "Country": "Afghanistan",
            "CountryCode": "AF",
            "Slug": "afghanistan",
            "NewConfirmed": 787,
            "TotalConfirmed": 18054,
            "NewDeaths": 6,
            "TotalDeaths": 300,
            "NewRecovered": 63,
            "TotalRecovered": 1585,
            "Date": "2020-06-05T17:51:15Z"
        },
        {
            "Country": "Albania",
            "CountryCode": "AL",
            "Slug": "albania",
            "NewConfirmed": 13,
            "TotalConfirmed": 1197,
            "NewDeaths": 0,
            "TotalDeaths": 33,
            "NewRecovered": 0,
            "TotalRecovered": 898,
            "Date": "2020-06-05T17:51:15Z"
        }
    ]
}

Solution

  • To fix this issue you need to modify your property from countries to Countries. Your keys should match the keys in the JSON.

    struct Countries : Codable {
        var Countries : [Country]
    }
    

    Or you could make the property name lowercased and the struct uppercased Swift style like this:

    struct Countries : Codable {
        var countries : [Country]
        enum CodingKeys: String, CodingKey {
             case countries = "Countries"
        }
    }