[英]Using Codable to parse nested JSON data
I'm trying to use Codable
to parse JSON data. 我正在尝试使用
Codable
解析JSON数据。 But having some problems when it comes down to an object with arrays. 但是当归结为带有数组的对象时会遇到一些问题。 I've been trying to follow following answer , but i'm getting an error
Type 'Feature' does not conform to protocol 'Encodable'
我一直在尝试遵循以下答案 ,但出现错误
Type 'Feature' does not conform to protocol 'Encodable'
The JSON data I want are the latitude and longitude data, but i'm struggling to hard to learn Codable
. 我想要的JSON数据是纬度和经度数据,但是我很难学习
Codable
。 I can also add that I tried to grab the id
and it worked fine, but when i'm trying to go deeper, it just gives me an error. 我还可以补充一点,我尝试获取该
id
,并且效果很好,但是当我尝试更深入时,它只会给我一个错误。
Any advice? 有什么建议吗? I do want to use
Codable
and not JSONSerialization
. 我确实想使用
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)
}
}
{
"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
]
]
The error the compiler is giving you is because your object doesn't conform to Encodable
编译器给您的错误是因为您的对象不符合
Encodable
If you just need to go JSON -> object and not the other way around then you can use Decodable
instead of Codable
. 如果只需要使用
Decodable
> object而不是其他方式,则可以使用Decodable
而不是Codable
。
Codable
requires conformance to Encodable
so you would also have to implement encode(to encoder: Encoder)
Codable
要求与Encodable
Codable
一致,因此您还必须实现Encodable
encode(to encoder: Encoder)
After you fix that then you also need to fix your parsing of the nested containers. 修复该问题之后,还需要修复对嵌套容器的解析。
Your inner geometry object has different keys than your outer object so you need a separate CodingKey
to pass. 内部几何对象与外部对象的键不同,因此需要单独的
CodingKey
进行传递。 You also need to go one level deeper than you currently are to get to your coordinates. 您还需要比当前深度更深一层才能到达坐标。
This version should work for the json in your question: 此版本适用于您问题中的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)
}
}
First of all if you want only to decode JSON adopt only Decodable
. 首先,如果只想解码JSON,则只能采用
Decodable
。 If you adopt Codable
and write a custom initializer you have to write also an encoder method. 如果采用
Codable
并编写自定义初始化程序,则还必须编写编码器方法。 This is the message of the error. 这是错误消息。
I recommend to decode the JSON into separate structs. 我建议将JSON解码为单独的结构。 This requires much less code.
这需要更少的代码。 Write an extension of
CLLocationCoordinate2D
as a wrapper for the coordinates to adopt Decodable
编写一个
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)
}
}
The rest are only a few lines 剩下的只有几行
struct Features: Decodable {
var features: [Feature]
}
struct Feature: Decodable {
let geometry : Geometry
}
struct Geometry: Decodable {
let coordinates : [CLLocationCoordinate2D]
}
You get the coordinates with 你得到的坐标
do {
let result = try JSONDecoder().decode(Features.self, from: data)
for feature in result.features {
print(feature.geometry.coordinates)
}
} catch { print(error) }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.