【问题标题】:Decode nested jsons swift快速解码嵌套的 jsons
【发布时间】:2020-07-21 18:41:39
【问题描述】:

大家好,我有一个关于 Swift 中的 Encodable 协议的小问题。

我有以下 json 文件:

let magicJson = """
{
    "value": [
        {
        "scheduleId": "magic@yahoo.com",
        "somethingEventMoreMagical": "000220000"
        }
    ]
}
""".data(using: .utf8)!

对于解码,我尽量避免创建两个都与可解码对象一起使用的对象,第一个对象包含第二个对象的数组。我想将该对象展平为如下所示:

struct MagicalStruct: Decodable {
    private enum CodingKeys: String, CodingKey {
        case value
    }
    
    private enum ScheduleCodingKeys: String, CodingKey {
        case roomEmail = "scheduleId"
    }
    
    let roomEmail: String
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let magicContainer = try container.nestedContainer(keyedBy: ScheduleCodingKeys.self, forKey: .value)
        roomEmail = try magicContainer.decode(String.self, forKey: ScheduleCodingKeys.roomEmail)
    }
}

但是,当我尝试以下代码时:JSONDecoder().decode(MagicalStruct.self, magicJson) 我知道它需要一个数组但得到一个字典。另一方面,当我使用JSONDecoder().decode([MagicalStruct].self, magicJson) 时,我得到它接收一个数组但需要一个字典。

有人知道为什么会这样吗?

【问题讨论】:

  • 您的输入 JSON 中似乎没有 scheduleId 键。
  • 我编辑错了json,里面也是scheduleId,让我编辑:D

标签: ios json swift decodable


【解决方案1】:

首先,当您使用以下方法解码结构时:

JSONDecoder().decode(MagicalStruct.self, magicJson)

您正在尝试提取单个对象:let roomEmail: String

但是,您的输入 JSON 包含带有电子邮件的对象数组。这意味着您的代码:

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    let magicContainer = try container.nestedContainer(keyedBy: ScheduleCodingKeys.self, forKey: .value)
    roomEmail = try magicContainer.decode(String.self, forKey: ScheduleCodingKeys.roomEmail)
}

尝试解码一封电子邮件,但有一个集合代替(在您的示例中带有 one 元素 - 这就是它可能令人困惑的原因)。

你的错误Expected to decode Dictionary<String, Any> but found an array instead也在线:

let magicContainer = try container.nestedContainer(keyedBy: ScheduleCodingKeys.self, forKey: .value)

你需要解码一个数组:

var magicContainer = try container.nestedUnkeyedContainer(forKey: .value)

但是你有一个带有scheduleIdsomethingEventMoreMagical 键的对象数组。您想如何将所有值分配给您的 let roomEmail: String 变量?


您可以改为解码字典:

let result = try JSONDecoder().decode([String: [MagicalStruct]].self, from: magicJson)

print(result["value"]!) // prints [MagicalStruct(roomEmail: "magic@yahoo.com")]

你可以简化你的MagicalStruct

struct MagicalStruct: Decodable {
    enum CodingKeys: String, CodingKey {
        case roomEmail = "scheduleId"
    }

    let roomEmail: String
}

【讨论】:

  • 嘿:) 谢谢你的回答,这确实是一个不错的解决方案,但我正在寻找的不是直接的方向/解决方案,而是为什么 Swift 不允许我描述的内容上面有可解码的。如果您有任何想法,请随时回答我很乐意听到更多意见/解决方案:)
  • @VladSima 我用更好的解释更新了我的答案。基本上所有问题都是因为您尝试将数组解析为单个对象。你需要选择你想要的:返回一个 [MagicalStruct] 的数组,将let roomEmail: String 设为一个数组而不是 String 或者只解析数组中的 first 电子邮件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 2023-03-20
  • 2019-03-22
  • 2020-02-22
  • 2018-04-29
  • 1970-01-01
相关资源
最近更新 更多