【问题标题】:Swift - How to use CodingKeys to map an Int to a custom enum?Swift - 如何使用 CodingKeys 将 Int 映射到自定义枚举?
【发布时间】:2020-06-22 10:36:43
【问题描述】:

我正在加载 JSON,其中包含我希望映射到枚举的整数

//Some JSON object
{
    "id": "....",
    "name": "Some Locomotive"
    "livery": 1,
    "generation": 1
    // other variables
}

我可以使用以下方式加载此 JSON:

struct Locomotive: Codable {
    var id, name: String
    var generation: Int   
    // var livery: Int -- Replace this with my own enum (below)
    var livery: Livery?

    private enum CodingKeys: CodingKey {
        case id, name, generation
        case livery = "livery" // complains of raw value issue
    }
}

目前,generaiton 和livery 都只是整数;但为了让我更容易编码,我希望使用将涂装 Integer 映射到枚举;所以而不是记住1 =绿色等;我只能说.green

但我无法将密钥涂装映射到我的枚举。

如果枚举没有原始类型,则枚举大小写不能有原始值

但我确信它确实如此;我已将枚举中的原始值定义为私有;

enum Livery : Codable {
    case green, red, blue, yellow
}

extension Livery {

    private enum RawValue: Int, Codable, CaseIterable {
        case green = 1, red, yellow, blue
    }

    private enum CodingKeys: Int, CodingKey {
        case green, red, blue, yellow
    }

init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let key = container.allKeys.first

        switch key {
        case .green:
            self = .green
        case .red:
            self = .red
        case .yellow:
            self = .yellow
        case .blue:
            self = .blue

        default:
            throw DecodingError.dataCorrupted(
                DecodingError.Context(
                    codingPath: container.codingPath,
                    debugDescription: "Error -- Unabled to decode."
                )
            )
        }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()

        switch self {
        case .green:
            try container.encode(RawValue.green)
        case .red:
            try container.encode(RawValue.red)
        case .yellow:
            try container.encode(RawValue.yellow)
        case .blue:
            try container.encode(RawValue.blue)
        }

    }
}

上述枚举对原始值进行解码并对其进行编码。

但是,我无法将父结构中的 Livery 映射到此枚举,我想知道如何做到这一点?

...

我想我也必须在这个结构中实现init(from decoder: Decoder)encode(to encoder: Encoder)——尤其是如果我以后想将我的数据保存到 JSON;但我不确定。

因此,我的查询是 - 如何将 JSON 提供的整数映射到自定义枚举以进行保存(编码)和加载(解码)。

感谢

【问题讨论】:

    标签: json swift enums decodable


    【解决方案1】:

    您可以大大简化您的代码,您只需要下面的代码。通过说你的枚举类型是 Int swift 可以合成正确的解码代码

    struct Locomotive: Codable {
        var id, name: String
        var generation: Int
        var livery: Livery?
    }
    
    enum Livery: Int, Codable {
        case green = 1, red, blue, yellow
    }
    

    【讨论】:

    • 那行得通——我以为我必须手动解码和映射每个值;谢谢!
    • 将其保存到磁盘(json文件);它还会保留整数吗?还是我还需要映射它?
    【解决方案2】:

    问题是您错误地声明了您的 Locomotive.CodingKeys enum。所有符合CodingKey 的枚举都需要有一个rawValue,但您声明了CodingKeys 而没有rawValue。给它一个 String rawValue 可以解决您的问题。

    struct Locomotive: Codable {
        var id, name: String
        var generation: Int
        // var livery: Int -- Replace this with my own enum (below)
        var livery: Livery?
    
        private enum CodingKeys: String, CodingKey {
            case id, name, generation, livery
        }
    }
    

    【讨论】:

    • 我试试看——也许我只是想把它复杂化。
    • 它抱怨数据格式无效。我确保两个编码键都有一个字符串键private enum CodingKeys: String, CodingKey {
    • 我认为 Livery 枚举中的编码键或 init(from decoder: Decoder) 在我尝试映射时会导致问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-30
    • 2021-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-11
    相关资源
    最近更新 更多