使用Codable在字典中解码日期

时间:2019-02-20 10:24:05

标签: json swift date dictionary codable

我正在尝试在Swift中使用Codables解码以下JSON字符串。

let json = """
{
    "todaysProvision": 235.50,
    "referenceDate": "2019-01-30",
    "lastSevenDays": {
        "2019-02-12": 235.20,
        "2019-02-11": 235.20,
        "2019-02-10": 235.20,
        "2019-02-09": 235.20,
        "2019-02-08": 235.20,
        "2019-02-07": 235.20,
        "2019-02-06": 235.20,
    }
}
"""

我当前的解码结构看起来像这样。

struct ProvisionInfo: Codable {

    let todaysProvision: Double
    let referenceDate: Date

}

JSONDecoderdateDecodingStrategy一起使用就像键referenceDate的一种魅力:

let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(df)

let decoded = try decoder.decode(ProvisionInfo.self, from: json.data(using: .utf8)!)

// decoded.todaysProvision -> 235.5
// decoded.referenceDate -> "Jan 30, 2019 at 12:00 AM"

对于JSON字典lastSevenDays,我想可以将结构更改为

struct ProvisionInfo: Codable {

    let todaysProvision: Double
    let referenceDate: Date
    let lastSevenDays: [Date: Double]

}

但是,这样我得到了解码错误

Playground execution terminated: An error was thrown and was not caught:
▿ DecodingError
  ▿ typeMismatch : 2 elements
    - .0 : Swift.Array<Any>
    ▿ .1 : Context
      ▿ codingPath : 1 element
        - 0 : CodingKeys(stringValue: "lastSevenDays", intValue: nil)
      - debugDescription : "Expected to decode Array<Any> but found a dictionary instead."
      - underlyingError : nil

解决此问题的唯一方法是添加一个自定义初始化程序来解码我的结构,该初始化程序将字典解析为[String: Double]并使用相同的[Date: Double]将该字典转换为DateFormatter

public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    todaysProvision = try container.decode(Double.self, forKey: .todaysProvision)
    referenceDate = try container.decode(Date.self, forKey: .referenceDate)
    let foo = try container.decode([String: Double].self, forKey: .lastSevenDays)
    lastSevenDays = Dictionary(uniqueKeysWithValues:foo.compactMap { (key, value) in
        guard let date = df.date(from: key) else { return nil }
        return (date, value)
    })
}

这是使用[Date: Double]解析Codables的唯一可能方法,还是我做错了什么?

谢谢!

0 个答案:

没有答案