如何快速解析此JSON格式 [英] How to parse this JSON format in swift

查看:92
本文介绍了如何快速解析此JSON格式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这种JSON格式:

I have this JSON format:

{
  "version":"7.0.19",
  "fields": ["ID","pm","age","pm_0","pm_1","pm_2","pm_3","pm_4","pm_5","pm_6","conf","pm1","pm_10","p1","p2","p3","p4","p5","p6","Humidity","Temperature","Pressure","Elevation","Type","Label","Lat","Lon","Icon","isOwner","Flags","Voc","Ozone1","Adc","CH"],
  "data":[[20,0.0,1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,97,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,null,null,null,1413,0,"Oakdale",40.603077,-111.83612,0,0,0,null,null,0.01,1]],
  "count":11880
}

但是我无法弄清楚如何使用Codable协议来解析json响应.

but I cannot work out how to use a Codable protocol to parse the json response.

这将是我想要的模型.

struct Point: Codable {
    let pm2: String?
    let latitude, longitude: Double?
    let temp: String?
    let iD: String?
    enum CodingKeys: String, CodingKey {
        case pm2 = "pm", temp = "Temperature", iD = "ID", latitude = "Lat", longitude = "Lon"
    }
}

这是json的URL

Here is a URL to the json

https://webbfoot.com/dataa.json

推荐答案

这很棘手,需要手动解码.原理是定义要解码的字段与对象属性之间的映射,然后根据属性的类型( String Double 等...),尝试对数据进行解码.

This one is tricky and requires manual decoding. The principle would be to define a mapping between the fields you expect to decode and the properties of your object, then depending on the type of the property (String, Double, etc...), attempt to decode the data.

第二,由于具有点数组,因此需要某种容器对象来保存该数组,例如:

Second, since you have an array of points, you need some kind of container object to hold the array, for example:

struct Points {
    var data: [Point] = []
}

首先,您的某些模型属性与数据中的类型不匹配,例如 iD String ,但是数据具有 Int .为简单起见,我将重新定义您的模型以匹配数据

First, some of your model properties don't match the type in the data, e.g. iD is a String, but the data has an Int. For simplicity, I'll redefine your model to match the data

struct Point {
    var pm2: Int? = nil
    var latitude: Double? = nil
    var longitude: Double? = nil
    var temp: Int? = nil
    var iD: Int? = nil
}

现在,为父容器 Points 编写手动解码器:

Now, write the manual decoder for the parent container Points:

extension Points: Decodable {   
    static let mapping: [String: PartialKeyPath<Point>] = [
        "pm":          \Point.pm2,
        "Lat":         \Point.latitude,
        "Lon":         \Point.longitude,
        "Temperature": \Point.temp,
        "ID":          \Point.iD
    ]

    enum CodingKeys: CodingKey { case fields, data }
    private struct Dummy: Decodable {} // see below why

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        let fields = try container.decode([String].self, forKey: .fields)
        var data = try container.nestedUnkeyedContainer(forKey: .data)

        while !data.isAtEnd {
            var row = try data.nestedUnkeyedContainer()

            var point = Point()          
            for field in fields {

                let keyPath = Points.mapping[field]
                switch keyPath {
                case let kp as WritableKeyPath<Point, String?>:
                    point[keyPath: kp] = try row.decodeIfPresent(String.self)
                case let kp as WritableKeyPath<Point, Int?>:
                    point[keyPath: kp] = try row.decodeIfPresent(Int.self)
                case let kp as WritableKeyPath<Point, Double?>:
                    point[keyPath: kp] = try row.decodeIfPresent(Double.self)
                default:
                    // this is a hack to skip this value
                    let _ = try? row.decode(Dummy.self)
                }
            }
            self.data.append(point)
        }
    }
}

有了它,就可以像这样对JSON进行解码:

Once you have that, you can decode the JSON like so:

let points = try JSONDecoder().decode(Points.self, from: jsonData)
let firstPoint = points.data[0] 

这篇关于如何快速解析此JSON格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆