在Swift中将不同的JSON feed解析为相同的Decodable结构 [英] Parsing different JSON feeds in Swift to the same Decodable struct
问题描述
我有两个不同的JSON feed,
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
}
和
{
"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
}
如我所见,我可以在init(from decoder:Decoder)
中使用Decodable
来做到这一点,但我无法将其包裹住并使它工作.
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.
推荐答案
一种解决方法是为每种json消息类型使用CodingKey枚举,然后在尝试使用一个枚举创建容器时捕获任何错误,而不是扔掉它并尝试使用另一个枚举创建一个容器
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.
这里是一个示例,其中data1和data2是问题中的两个样本
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)
}
地点(名称:"02-STATION",纬度:43.25394,长度:-2.93844)
地方(名称:科菲街和康诺弗街",经纬度:40.677236,外观:-74.015665)
Places(name: "02-STATION", lat: 43.25394, lng: -2.93844)
Places(name: "Coffey St & Conover St", lat: 40.677236, lng: -74.015665)
这篇关于在Swift中将不同的JSON feed解析为相同的Decodable结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!