在Swift中将不同的JSON feed解析为相同的Decodable结构 [英] Parsing different JSON feeds in Swift to the same Decodable struct

查看:60
本文介绍了在Swift中将不同的JSON feed解析为相同的Decodable结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个不同的JSON feed,

I have two different JSON feeds,

{
 "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"
}

我想要解析填充以下结构的两个供稿,

What I would like is to parse both feeds filling the following structure,


struct Places: Codable {

    var name: String
    let lat: Double
    let lng: Double
}

如我所见,我可以在init(from decoder:Decoder)中使用Decodable来做到这一点,但我无法将其包裹住并使它工作.

As I've seen I can do this using Decodable in the init(from decoder:Decoder) but I can't wrap my head around it and make it work.

推荐答案

一种解决方法是为每种json消息类型使用CodingKey枚举,然后在尝试使用一个枚举创建容器时捕获任何错误,而不是扔掉它并尝试使用另一个枚举创建一个容器

One way to solve this is to have a CodingKey enum for each json message type and then when trying to create a container using one enum we catch any error instead of throwing it and tries to create a container using the other enum

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)
    }
}

也许最后一部分可以使用泛型重写.

Maybe the last part can be rewritten using generics.

这里是一个示例,其中data1和data2是问题中的两个样本

Here is an example where data1 and data2 are the two samples from the question

do {

    for data in [data1, data2] {
        let result = try JSONDecoder().decode(Places.self, from: data)
        print(result)
    }
} catch {
    print(error)
}

地点(名称:"02-STATION",纬度:43.25394,长度:-2.93844)
地方(名称:科菲街和康诺弗街",经纬度:40.677236,外观:-74.015665)

Places(name: "02-STATION", lat: 43.25394, lng: -2.93844)
Places(name: "Coffey St & Conover St", lat: 40.677236, lng: -74.015665)

这篇关于在Swift中将不同的JSON feed解析为相同的Decodable结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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