问题
I have two different JSON feeds,
{
"uid":9018823,
"lat":43.25394,
"lng":-2.93844,
"bike":false,
"name":"02-STATION",
"address":null,
"spot":true,
"number":3388,
"bikes":3,
"booked_bikes":0,
"bike_racks":20,
"free_racks":16
}
and
{
"address":null,"last_updated":1580546431,
"renting":1,"returning":1,"uid":"3348"},
"free_bikes":17,
"id":"0a0d9d6e93abd05548c672b60bfa9099",
"latitude":40.677236,
"longitude":-74.015665,
"station_name":"Coffey St & Conover St",
"timestamp":"2020-02-01T09:26:31.254000Z"
}
What I would like is to parse both feeds filling the following structure,
struct Places: Codable {
var name: String
let lat: Double
let lng: Double
}
As I've seen I can do this using Decodable
in the init(from decoder:Decoder)
but I can't wrap my head around it and make it work.
回答1:
One way to solve this is to have a CodingKey enum for each json message type and then when trying to create a container using one enum we catch any error instead of throwing it and tries to create a container using the other enum
struct Places: Decodable {
let name: String
let lat: Double
let lng: Double
enum CodingKeys1: String, CodingKey {
case name
case lat
case lng
}
enum CodingKeys2: String, CodingKey {
case name = "station_name"
case lat = "latitude"
case lng = "longitude"
}
init(from decoder: Decoder) throws {
do {
let container = try decoder.container(keyedBy: CodingKeys1.self)
try self.init(container)
} catch {
let container = try decoder.container(keyedBy: CodingKeys2.self)
try self.init(container)
}
}
private init(_ container: KeyedDecodingContainer<CodingKeys1>) throws {
name = try container.decode(String.self, forKey: .name)
lat = try container.decode(Double.self, forKey: .lat)
lng = try container.decode(Double.self, forKey: .lng)
}
private init(_ container: KeyedDecodingContainer<CodingKeys2>) throws {
name = try container.decode(String.self, forKey: .name)
lat = try container.decode(Double.self, forKey: .lat)
lng = try container.decode(Double.self, forKey: .lng)
}
}
Maybe the last part can be rewritten using generics.
Here is an example where data1 and data2 are the two samples from the question
do {
for data in [data1, data2] {
let result = try JSONDecoder().decode(Places.self, from: data)
print(result)
}
} catch {
print(error)
}
Places(name: "02-STATION", lat: 43.25394, lng: -2.93844)
Places(name: "Coffey St & Conover St", lat: 40.677236, lng: -74.015665)
来源:https://stackoverflow.com/questions/60015691/parsing-different-json-feeds-in-swift-to-the-same-decodable-struct