Apoorva Reed
Apoorva Reed

Reputation: 71

Getting error while trying to decode json through jsondecoder

This is my json I am trying to decode using JSONDecoder but having hard time as its not able to do it. can someone help with what struct and how can I decode?

{
"Afghanistan": [
    {
        "city": "Kabul",
        "lat": "34.5167",
        "lng": "69.1833",
        "state": "Kābul",
        "country": "Afghanistan"
    },
    {
        "city": "Karukh",
        "lat": "34.4868",
        "lng": "62.5918",
        "state": "Herāt",
        "country": "Afghanistan"
    },
    {
        "city": "Zarghūn Shahr",
        "lat": "32.85",
        "lng": "68.4167",
        "state": "Paktīkā",
        "country": "Afghanistan"
    }
],
"Albania": [
    {
        "city": "Tirana",
        "lat": "41.3275",
        "lng": "19.8189",
        "state": "Tiranë",
        "country": "Albania"
    },

    {
        "city": "Pukë",
        "lat": "42.0333",
        "lng": "19.8833",
        "state": "Shkodër",
        "country": "Albania"
    }
]}

what do you suggest to decode it?

I am trying this

let locationData: Countries = load("Countries.json")

func load<T: Decodable>(_ filename: String) -> T {
let data: Data

guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
else {
    fatalError("Couldn't find \(filename) in main bundle.")
}

do {
    data = try Data(contentsOf: file)
} catch {
    fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}

do {
    let decoder = JSONDecoder()
    return try decoder.decode(T.self, from: data)
} catch {
    fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
 }

struct Country: Codable, Identifiable {
var id = UUID()

let city, lat, lng: String
let state: String?
let country: String
}

typealias Countries = [String: [Country]]

But getting this error

Couldn't parse Countries.json as Dictionary>: keyNotFound(CodingKeys(stringValue: "id", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Albania", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"id\", intValue: nil) (\"id\").", underlyingError: nil)):

Upvotes: 1

Views: 2423

Answers (2)

Joakim Danielson
Joakim Danielson

Reputation: 51920

Since the property id is not part of the json you need to define what properties the decoder should decode by adding a CodingKey enum to Country

enum CodingKeys: String, CodingKey {
    case city, lat, lng, state, country
}

The CodingKey enum also gives you the opportunity to use better names for your struct properties if you want to and map them in the enum to the json keys.

struct Country: Codable, Identifiable {
    var id = UUID()

    let city: String
    let latitude: String
    let longitude: String
    let state: String?
    let country: String

    enum CodingKeys: String, CodingKey {
        case city
        case latitude = "lat"
        case longitude = "lng"
        case state, country
    }
}

Upvotes: 2

Max
Max

Reputation: 22325

This is the relevant part of the error: keyNotFound(CodingKeys(stringValue: "id", intValue: nil). It's telling you that it's looking for an "id" key in each JSON object and isn't finding it.

It is looking for an id because the default implementation of the Codable protocol for structs tries to deserialize all properties you define. You defined a var id property, so it's looking for that.

Since you don't want to deserialize the id property, you need to customize your struct so that it doesn't use the default implementation. The documentation for how to do that is here: Encoding and Decoding Custom Types

In your case you just need to define a CodingKeys enum inside your struct so that it knows which keys to look for:

enum CodingKeys: String, CodingKey {
    case city, lat, lng, state, country
}

Upvotes: 1

Related Questions