Swift Codable解码以更改JSON并忽略某些字段

时间:2019-05-28 11:44:30

标签: json swift

我有一些REST API,它返回JSON。此API由不止一种服务(移动,Web等)使用,它返回的JSON中包含的字段超出了我的需要,并且其中一些其他字段可以每周更改。 例如,我有这样的JSON:

  

{“名称”:“丰田普锐斯”,“马力”:134,“里程”:123241,   “制成品”:2017年,“位置”:“一个城市”,“产地”:“日本”,
  “ convert”:true //更多属性随即...}

在移动应用程序中,我只需要解码字段:名称,马力和制造日期,其余的可以忽略。此外,某些字段(例如起源)以前不存在,但几天前已添加。

问题是如何编写防弹解码器,如果JSON中的某些更改不影响应用程序中的模型,该解码器不会中断?另外,我在服务器的输出JSON中没有任何内容,也无法影响它。我只获取数据,而我必须处理得到的东西。

我已经为操场写了一些实验代码(没有打印出汽车):

import UIKit

struct Car: Codable
{
    let name: String
    let horsePower: Int
    let selected: Bool //this is used as additional property inside my app to mark selected cars
    let index: Int //this is used as additional property inside my app for some indexing purposes

    enum CodingKeys: String, CodingKey
    {
        case name
        case horsePower = "horsepower"
        case selected
        case index
    }

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

        selected = false
        index = 0

        name = try values.decode(String.self, forKey: .name)
        horsePower = try values.decode(Int.self, forKey: .horsePower)
    }
}

let json = "{\"name\": \"Toyota Prius\",\"horsepower\": 134, \"convert\", true}"

let data = json.data(using: .utf8)

if let car = try? JSONDecoder().decode(Car.self, from: data!)
{
    //does not print... :(
    print(car)
}

我想在示例中打印汽车,但是大多数情况下,如果JSON被更改,其工作证明代码不会损坏。 还有没有办法以某种方式获得解码错误描述? 我知道Apple文档中有很多内容,但是大多数情况下,这对我来说太混乱了,我找不到解决此问题的有用示例。

1 个答案:

答案 0 :(得分:2)

首先从不 try? JSONDecoder...catch始终将错误并打印出来。 DecodingErrors非常具有描述性。他们会确切告诉您哪里出了问题,甚至出了什么地方。

在您的示例中,您将获得

  

“给定的数据不是有效的JSON。...字符52周围的对象没有键值。”

convert\"之后的错误逗号(而不是冒号)

要仅解码特定密钥,请相应地声明CodingKeys并删除init方法。 selectedindex最有可能是可变的,因此将它们声明为具有默认值的变量。

如果后端更改JSON结构,则会收到错误消息。无论解析API如何,解码过程都会中断。

struct Car: Codable
{
    let name: String
    let horsePower: Int
    let convert : Bool

    var selected = false
    var index = 0

    enum CodingKeys: String, CodingKey {
        case name, horsePower = "horsepower", convert
    }
}

let json = """
{"name":"Toyota Prius","horsepower":134,"convert":true}
"""

let data = Data(json.utf8)

do {
    let car = try JSONDecoder().decode(Car.self, from: data)
    print(car)
} catch { print(error) }