解码嵌套的 json swift

Decode nested jsons swift

大家好,我有一个与 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) 时,我得到它接收一个数组但需要一个字典。

有谁知道为什么会这样?

首先,当您解码结构时使用:

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
}