将 Swift 中的不同 JSON 提要解析为相同的 Decodable 结构
Parsing different JSON feeds in Swift to the same Decodable struct
我有两个不同的 JSON 供稿,
{
"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"
}
我想要解析填充以下结构的两个提要,
struct Places: Codable {
var name: String
let lat: Double
let lng: Double
}
正如我所见,我可以在 init(from decoder:Decoder)
中使用 Decodable
来做到这一点,但我无法全神贯注地让它发挥作用。
解决这个问题的一种方法是为每个 json 消息类型设置一个 CodingKey 枚举,然后当尝试使用一个枚举创建容器时,我们会捕获任何错误而不是抛出它并尝试创建一个容器使用另一个枚举
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)
}
}
也许最后一部分可以使用泛型重写。
这是一个示例,其中 data1 和 data2 是问题中的两个样本
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)
我有两个不同的 JSON 供稿,
{
"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"
}
我想要解析填充以下结构的两个提要,
struct Places: Codable {
var name: String
let lat: Double
let lng: Double
}
正如我所见,我可以在 init(from decoder:Decoder)
中使用 Decodable
来做到这一点,但我无法全神贯注地让它发挥作用。
解决这个问题的一种方法是为每个 json 消息类型设置一个 CodingKey 枚举,然后当尝试使用一个枚举创建容器时,我们会捕获任何错误而不是抛出它并尝试创建一个容器使用另一个枚举
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)
}
}
也许最后一部分可以使用泛型重写。
这是一个示例,其中 data1 和 data2 是问题中的两个样本
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)