使用 Codable 解析嵌套的 JSON 数据
Posted
技术标签:
【中文标题】使用 Codable 解析嵌套的 JSON 数据【英文标题】:Using Codable to parse nested JSON data 【发布时间】:2018-04-27 15:15:31 【问题描述】:我正在尝试使用 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
]
]
【问题讨论】:
它会给你什么错误? 如上所述:Type 'Feature' does not conform to protocol 'Encodable
@Andy
【参考方案1】:
编译器给你的错误是因为你的对象不符合Encodable
如果您只需要使用 JSON -> 对象而不是相反,那么您可以使用 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)
【讨论】:
它运行良好!非常感谢你!我会把它标记为答案! 我有另一个关于这个的问题。通过使用上面的代码,我只得到坐标数组的第一个对象。我试图制作另一个结构,但这一切都给了我 nil 的价值 看看@vadian 的回答。它将所有坐标拉成一个数组 是的,我试过了,但是当我必须获取更多信息(例如属性值 + 坐标)时,它似乎不起作用。我会尝试使用 vadian 所说的新结构,因为坐标在数组中的数组中。【参考方案2】:首先,如果您只想解码 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)
【讨论】:
您是否有将模型用作可编码模型的示例,我们可以将模型用于核心数据保存模型和 json 解析模型?我不想为代码数据实体和单独的模型对象创建自定义子类。我想为两者使用一 (1) 个模型类,它可以子类化可编码和 nsmanagedobject 或任何东西。在我们的旧项目中,我们使用了 2 个模型。在转换之前,我们使用 mapper 方法将 nsmanageobejct 转换为 nsobject(核心数据获取)和 nsobject 转换为 nsmanagedobejct(核心数据保存)。有几天我一直在为这样的例子而苦苦挣扎:(以上是关于使用 Codable 解析嵌套的 JSON 数据的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Codable 和 Swift 解析这个嵌套的 JSON?
iOS swift Codable 不能与 Alamofire 一起使用 JSON 嵌套数据?