迅速解码嵌套的jsons

时间:2020-07-21 18:41:39

标签: ios json swift decodable

大家好,我对Swift中的Encodable协议有个疑问。

我有以下json文件:

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

对于解码,我尝试避免创建两个都与Decodable一起使用的对象,第一个对象包含第二个对象的数组。我想将该对象压扁成这样:

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)时,得到的是它接收到一个数组但需要一个字典。

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

1 个答案:

答案 0 :(得分: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
}