【问题标题】:Swift Decodable JSON dictionary with heterogeneous array具有异构数组的 Swift 可解码 JSON 字典
【发布时间】:2017-08-16 15:35:12
【问题描述】:

我有一些以以下格式返回的 JSON,

{
"Random Word": [
    [
        "2017-08-10",
        6
    ],
    [
        "2017-08-11",
        6
    ],
    [
        "2017-08-15",
        4
    ]
],
"Another Random Word": [
    [
        "2017-08-10",
        4
    ],
    [
        "2017-08-11",
        4
    ],
    [
        "2017-08-12",
        1
    ],
    [
        "2017-08-14",
        2
    ],
    [
        "2017-08-15",
        4
    ],
    [
        "2017-08-16",
        1
    ]
]
}

问题是'key'每次都会不同,'value'包含一个异构的字符串数组(应该转换为日期)和整数。

有没有办法使用 Swift 的 Decodable 协议把它变成对象?

这是一个结构体,它可以被解码为,

struct MyJSONData: Decodable {

    var myInfo: Dictionary<String, [[Any]]>?
    ...
}

但是,如果有更好的方法来构建结构,我会全力以赴!

提前致谢。

【问题讨论】:

  • 您不能使用 Any/AnyObject。你的数据结构稳定吗?我的意思是,它总是按这个顺序是 String 和 Int 吗?
  • @nathan Any/AnyObject 不符合 Codable 协议,所以这并没有什么帮助。

标签: json swift4 decodable


【解决方案1】:

我很确定您的情况与我最近发布的一个问题相似:Flattening JSON when keys are known only at runtime

如果是这样,您可以使用以下解决方案:

struct MyJSONData: Decodable {
    var dates = [Any]()

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()

        // Only use first item
        let stringItem = try container.decode(String.self)
        dates.append(stringItem)
        let numberItem = try container.decode(Int.self)
        dates.append(numberItem)
    }
}

let decoded = try! JSONDecoder().decode([String : [MyJSONData]].self, from: jsonData).values
// Returns an Array of MyJSONData

工作解决方案:http://swift.sandbox.bluemix.net/#/repl/59949d74677f2b7ec84046c8

【讨论】:

    【解决方案2】:

    我正在使用一个 API,它使用像你这样的异构数据对 JSON 数组进行编码,但即使是列的顺序也是事先不知道的 :(

    一般来说,我强烈建议不要将数据存储在异构数组中。你很快就会忘记什么索引代表什么属性,更不用说不断地来回转换了。相反,当您从数组解码时,创建一个数据模型来存储它。

    另外需要注意的是,您的日期不是JSONDecoder 默认情况下所期望的。它需要 ISO 8601 格式 (yyyy-MM-ddTHH:mm:ssZ),而日期字符串中缺少时间部分。您可以通过提供自定义 DateFormatter 来告诉 JSONDecoder 要做什么:

    struct WordData: Decodable {
        var date: Date
        var anInt: Int
    
        init(from decoder: Decoder) throws {
            var container = try decoder.unkeyedContainer()
            self.date = try container.decode(Date.self)
            self.anInt = try container.decode(Int.self)
        }
    }
    
    var dateFormatter = DateFormatter()
    dateFormatter.locale = Locale(identifier: "en_us_POSIX")
    dateFormatter.timeZone = TimeZone(identifier: "UTC")
    dateFormatter.dateFormat = "yyyy-MM-dd"
    
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .formatted(dateFormatter)
    
    let words = try decoder.decode([String: [WordData]].self, from: jsonData)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-05
      • 1970-01-01
      • 2016-01-02
      • 1970-01-01
      • 2021-07-09
      相关资源
      最近更新 更多