Swift 可编码 : Use a parent's key as as value

标签 swift codable decodable jsondecoder

我有一个 JSON,其 ID 位于根级别:

{
    "12345": {
        "name": "Pim"
    },
    "54321": {
        "name": "Dorien"
    }
}

我的目标是使用 Codable 创建同时具有名称和 ID 属性的 User 对象数组。

struct User: Codable {
    let id: String
    let name: String
}

我知道如何使用 Codable with a single root level key我知道如何工作with unknown keys 。但我在这里尝试做的是两者的结合,我不知道下一步该做什么。

这是我到目前为止得到的:(您可以将其粘贴到 Playground 中)

import UIKit

var json = """
{
    "12345": {
        "name": "Pim"
    },
    "54321": {
        "name": "Dorien"
    }
}
"""

let data = Data(json.utf8)

struct User: Codable {
    let name: String
}

let decoder = JSONDecoder()
do {
    let decoded = try decoder.decode([String: User].self, from: data)
    decoded.forEach { print($0.key, $0.value) }
    // 54321 User(name: "Dorien")
    // 12345 User(name: "Pim")
} catch {
    print("Failed to decode JSON")
}

这就是我想做的:

let decoder = JSONDecoder()
do {
    let decoded = try decoder.decode([User].self, from: data)
    decoded.forEach { print($0) }
    // User(id: "54321", name: "Dorien")
    // User(id: "12345", name: "Pim")
} catch {
    print("Failed to decode JSON")
}

非常感谢任何帮助。

最佳答案

您可以使用自定义编码 key 并如下设置用户来解析未知 key ,

struct CustomCodingKey: CodingKey {

    let intValue: Int?
    let stringValue: String

    init?(stringValue: String) {
        self.intValue = Int(stringValue)
        self.stringValue = stringValue
    }

    init?(intValue: Int) {
        self.intValue = intValue
        self.stringValue = "\(intValue)"
    }
}

struct UserInfo: Codable {
    let name: String
}

struct User: Codable {
    var id: String = ""
    var info: UserInfo?

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CustomCodingKey.self)
        if let key = container.allKeys.first {
            self.id = key.stringValue
            self.info = try container.decode(UserInfo.self, forKey: key)
        }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CustomCodingKey.self)
        if let key = CustomCodingKey(stringValue: self.id) {
            try container.encode(self.info, forKey: key)
        }
    }
}

let decoder = JSONDecoder()
do {
    let decoded = try decoder.decode(User.self, from: data)
    print(decoded.id) // 12345
    print(decoded.info!.name) // Pim
} catch {
    print("Failed to decode JSON")
}

关于Swift 可编码 : Use a parent's key as as value,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58266456/

相关文章:

ios - 使用未声明的类型 "ViewController"

ios - 如何将模型类字典中的值存储在 Array/NSMutableArray 中?

swift - 如何将符合 Codable 协议(protocol)的枚举保存到 UserDefaults?

json - 使用 Swift Decodable 解析 JSON 时出现类型不匹配错误

json - 如何快速将这个异构对象与模型映射?

swift - 无法从解码器获取字典

ios - didSelectAnnotationView 未调用

swift - 在 Swift 5 中使用动态 URL 的 WKWebView 深色和浅色模式

ios - 参数类型不符合 Encodable

swift - 将类型为 Any 的 Swift Encodable 类转换为字典