Reputation: 71
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
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
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