【问题标题】:Nested JSON into nested dictionary with swift用swift将JSON嵌套到嵌套字典中
【发布时间】:2017-07-19 14:40:31
【问题描述】:

我使用新的 Codable 协议将结构转换为 JSON,然后转换为字典以进行测试。问题是结构中的字典变量没有被转换回来并保持Any而不是[Int: String]

struct Person: Codable {
    var name: String?
    var history: [Int: String]

    init() {
        self.name = "Name"
        history = [0: "Test"]
    }
}

let person = Person()

let jsonData = try JSONEncoder().encode(person)

let result = try JSONSerialization.jsonObject(with: jsonData, options: [])

let dictionary = result as? [String: Any]

print(dictionary)

这给了我以下结果

Optional(["history": {
    0 = Test;
}, "name": Name])

当我期望的时候

Optional(["history":[0: "Test"]], "name": "Test"])

我将不胜感激任何关于为什么会发生这种情况的解释,或者更好的是如何基本上进行深度 JSON 序列化的解决方案。

我正在添加一个展示问题的游乐场: https://www.dropbox.com/s/igpntk7az0hevze/JSONSerialisation.playground.zip

【问题讨论】:

  • 您为什么希望它看起来像这样?您正在打印的字典是完整的字典,数据似乎正是它应该是的。请记住,[Int: String] 不是一个数组,它是一个字典,{0 = Test;} 是当您将字典打印到控制台进行调试时 Swift 格式化字典的方式......在我看来,您的代码工作正常。跨度>
  • 嗨,donnywals,实际上这不是 swift 打印字典的方式。如果我将字典定义为let sampleDictionary: [String: Any] = ["history":[0: "Test"], "name": "Test"],然后将其打印为print(sampleDictionary),则结果为["history": [0: "Test"], "name": "Test"]。如果我尝试使用let history = dictionary["history"] as? [Int: String] 访问历史记录,则该值为 nil,因为它不是字典。
  • 哎呀......你似乎是绝对正确的丹尼斯!

标签: json swift dictionary nsjsonserialization codable


【解决方案1】:

正如您使用JSONEncoder 进行编码一样,您也可以使用JSONDecoder 来解码json 数据。在这种情况下,history 是一个不是默认类型之一的字典,因此添加 init(from decoder: Decoder) 和自定义将是获得预期字典的一种解决方法。

struct Person: Codable {
    var name: String
    var history: [Int: String]

    init() {
        self.name = "Name"
        history = [0: "Test"]
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? "Failed to decode name"
        self.history = try container.decodeIfPresent([Int: String].self, forKey: .history) ?? [-1: "Failed to decode history"]
    }
}

let person = Person()
do {
    let jsonData = try JSONEncoder().encode(person)

    if let result = try? JSONDecoder().decode(Person.self, from: jsonData) {
        print(result)
    }
} catch {
    print(error.localizedDescription)    
}

【讨论】:

  • 谢谢Lawliet,你说的很对,我可以把它解码成一个人,我什至不需要覆盖解码器的init,因为实际上,字典被解析得很好。
【解决方案2】:

原来它是一本字典,它只是打印出来就好像它不是字典一样。我认为它不是字典的原因是调用

let history = dictionary["history"] as? [Int: String] 

会导致 nil,但原因是 JSON 显然无法处理 [Int: String]。相反,我的[Int: String] 已经(可能是通过JSONSerialization.jsonObject(with: jsonData, options: []) 函数)变成了[String: Any]

let history = dictionary["history"] as? [String: String]

工作得很好。

我仍然不明白为什么控制台打印出来的东西像大括号一样,也许是一个错误?

【讨论】:

    猜你喜欢
    • 2018-05-31
    • 2019-05-02
    • 2015-08-25
    • 2021-07-18
    • 1970-01-01
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    • 2019-11-29
    相关资源
    最近更新 更多