使用 Codable 解析嵌套的 JSON 数据
Using Codable to parse nested JSON data
我正在尝试使用 Codable
来解析 JSON 数据。但是当涉及到带有数组的对象时会遇到一些问题。我一直在尝试关注 answer,但出现错误 Type 'Feature' does not conform to protocol 'Encodable'
我要的JSON数据是经纬度数据,但是学起来很吃力Codable
。我还可以补充一点,我试图抓住 id
并且它工作正常,但是当我试图更深入时,它只会给我一个错误。
有什么建议吗?我确实想使用 Codable
而不是 JSONSerialization
.
我的结构(到目前为止)
struct Features: Codable {
var features: [Feature]
}
struct Feature: Codable {
var lat: Double
var long: Double
enum CodingKeys: String, CodingKey {
case geometry
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let geometry = try values.nestedContainer(keyedBy: CodingKeys.self, forKey: .geometry)
var coordinates = try geometry.nestedUnkeyedContainer(forKey: .geometry)
long = try coordinates.decode(Double.self)
lat = try coordinates.decode(Double.self)
}
}
JSON 回应
{
"type":"FeatureCollection",
"totalFeatures":1761,
"features":[
{
"type":"Feature",
"id":"LTFR_P_RORELSEHINDRADE.3179814",
"geometry":{
"type":"LineString",
"coordinates":[
[
17.929374,
59.387507
],
[
17.929364,
59.387493
]
]
},
"geometry_name":"GEOMETRY",
"properties":{
"FID":3179814,
"FEATURE_OBJECT_ID":2406812,
"FEATURE_VERSION_ID":1,
"EXTENT_NO":2,
"VALID_FROM":"2008-10-09T22:00:00Z",
"CITATION":"0180 2008-09122",
"STREET_NAME":"Visbyringen",
"CITY_DISTRICT":"Rinkeby",
"PARKING_DISTRICT":"<Område saknas>",
"ADDRESS":"Visbyringen 4",
"VF_METER":12,
"VF_PLATS_TYP":"Reserverad p-plats rörelsehindrad",
"RDT_URL":"https://rdt.transportstyrelsen.se/rdt/AF06_View.aspx?BeslutsMyndighetKod=0180&BeslutadAr=2008&LopNr=09122"
}
}
]
}
感兴趣的数据
"coordinates":[
[
17.929374,
59.387507
],
[
17.929364,
59.387493
]
]
编译器给你的错误是因为你的对象不符合Encodable
如果您只需要去 JSON -> object 而不是相反,那么您可以使用 Decodable
而不是 Codable
。
Codable
要求符合 Encodable
因此您还必须实施 encode(to encoder: Encoder)
修复该问题后,您还需要修复对嵌套容器的解析。
您的内部几何对象与外部对象具有不同的键,因此您需要一个单独的 CodingKey
才能通过。您还需要比当前更深一层才能到达您的坐标。
此版本应该适用于您问题中的 json:
struct Features: Decodable {
var features: [Feature]
}
struct Feature: Decodable {
var lat: Double
var long: Double
enum CodingKeys: String, CodingKey {
case geometry
}
enum GeometryKeys: String, CodingKey {
case coordinates
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let geometry = try values.nestedContainer(keyedBy: GeometryKeys.self, forKey: .geometry)
var coordinates = try geometry.nestedUnkeyedContainer(forKey: .coordinates)
var longLat = try coordinates.nestedUnkeyedContainer()
long = try longLat.decode(Double.self)
lat = try longLat.decode(Double.self)
}
}
首先如果你只想解码JSON只采用Decodable
。如果采用 Codable
并编写自定义初始化程序,则还必须编写编码器方法。这是错误消息。
我建议将 JSON 解码为单独的结构。这需要更少的代码。编写 CLLocationCoordinate2D
的扩展作为坐标采用 Decodable
的包装器
import CoreLocation
extension CLLocationCoordinate2D : Decodable {
public init(from decoder: Decoder) throws {
var arrayContainer = try decoder.unkeyedContainer()
let lat = try arrayContainer.decode(CLLocationDegrees.self)
let lng = try arrayContainer.decode(CLLocationDegrees.self)
self.init(latitude: lat, longitude: lng)
}
}
剩下的只有几行
struct Features: Decodable {
var features: [Feature]
}
struct Feature: Decodable {
let geometry : Geometry
}
struct Geometry: Decodable {
let coordinates : [CLLocationCoordinate2D]
}
你得到坐标
do {
let result = try JSONDecoder().decode(Features.self, from: data)
for feature in result.features {
print(feature.geometry.coordinates)
}
} catch { print(error) }
我正在尝试使用 Codable
来解析 JSON 数据。但是当涉及到带有数组的对象时会遇到一些问题。我一直在尝试关注 answer,但出现错误 Type 'Feature' does not conform to protocol 'Encodable'
我要的JSON数据是经纬度数据,但是学起来很吃力Codable
。我还可以补充一点,我试图抓住 id
并且它工作正常,但是当我试图更深入时,它只会给我一个错误。
有什么建议吗?我确实想使用 Codable
而不是 JSONSerialization
.
我的结构(到目前为止)
struct Features: Codable {
var features: [Feature]
}
struct Feature: Codable {
var lat: Double
var long: Double
enum CodingKeys: String, CodingKey {
case geometry
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let geometry = try values.nestedContainer(keyedBy: CodingKeys.self, forKey: .geometry)
var coordinates = try geometry.nestedUnkeyedContainer(forKey: .geometry)
long = try coordinates.decode(Double.self)
lat = try coordinates.decode(Double.self)
}
}
JSON 回应
{
"type":"FeatureCollection",
"totalFeatures":1761,
"features":[
{
"type":"Feature",
"id":"LTFR_P_RORELSEHINDRADE.3179814",
"geometry":{
"type":"LineString",
"coordinates":[
[
17.929374,
59.387507
],
[
17.929364,
59.387493
]
]
},
"geometry_name":"GEOMETRY",
"properties":{
"FID":3179814,
"FEATURE_OBJECT_ID":2406812,
"FEATURE_VERSION_ID":1,
"EXTENT_NO":2,
"VALID_FROM":"2008-10-09T22:00:00Z",
"CITATION":"0180 2008-09122",
"STREET_NAME":"Visbyringen",
"CITY_DISTRICT":"Rinkeby",
"PARKING_DISTRICT":"<Område saknas>",
"ADDRESS":"Visbyringen 4",
"VF_METER":12,
"VF_PLATS_TYP":"Reserverad p-plats rörelsehindrad",
"RDT_URL":"https://rdt.transportstyrelsen.se/rdt/AF06_View.aspx?BeslutsMyndighetKod=0180&BeslutadAr=2008&LopNr=09122"
}
}
]
}
感兴趣的数据
"coordinates":[
[
17.929374,
59.387507
],
[
17.929364,
59.387493
]
]
编译器给你的错误是因为你的对象不符合Encodable
如果您只需要去 JSON -> object 而不是相反,那么您可以使用 Decodable
而不是 Codable
。
Codable
要求符合 Encodable
因此您还必须实施 encode(to encoder: Encoder)
修复该问题后,您还需要修复对嵌套容器的解析。
您的内部几何对象与外部对象具有不同的键,因此您需要一个单独的 CodingKey
才能通过。您还需要比当前更深一层才能到达您的坐标。
此版本应该适用于您问题中的 json:
struct Features: Decodable {
var features: [Feature]
}
struct Feature: Decodable {
var lat: Double
var long: Double
enum CodingKeys: String, CodingKey {
case geometry
}
enum GeometryKeys: String, CodingKey {
case coordinates
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let geometry = try values.nestedContainer(keyedBy: GeometryKeys.self, forKey: .geometry)
var coordinates = try geometry.nestedUnkeyedContainer(forKey: .coordinates)
var longLat = try coordinates.nestedUnkeyedContainer()
long = try longLat.decode(Double.self)
lat = try longLat.decode(Double.self)
}
}
首先如果你只想解码JSON只采用Decodable
。如果采用 Codable
并编写自定义初始化程序,则还必须编写编码器方法。这是错误消息。
我建议将 JSON 解码为单独的结构。这需要更少的代码。编写 CLLocationCoordinate2D
的扩展作为坐标采用 Decodable
import CoreLocation
extension CLLocationCoordinate2D : Decodable {
public init(from decoder: Decoder) throws {
var arrayContainer = try decoder.unkeyedContainer()
let lat = try arrayContainer.decode(CLLocationDegrees.self)
let lng = try arrayContainer.decode(CLLocationDegrees.self)
self.init(latitude: lat, longitude: lng)
}
}
剩下的只有几行
struct Features: Decodable {
var features: [Feature]
}
struct Feature: Decodable {
let geometry : Geometry
}
struct Geometry: Decodable {
let coordinates : [CLLocationCoordinate2D]
}
你得到坐标
do {
let result = try JSONDecoder().decode(Features.self, from: data)
for feature in result.features {
print(feature.geometry.coordinates)
}
} catch { print(error) }