Swift - 如何使用 CodingKeys 将 Int 映射到自定义枚举?

Swift - How to use CodingKeys to map an Int to a custom enum?

我正在加载 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
    }
}

目前世代和涂装都是整数;但是为了让我的编码更容易,我希望使用 map the livery Integer to an enum;所以与其记住 1 = 绿色,等等;我只能说 .green

但是我无法将键制服映射到我的枚举。

Enum case cannot have a raw value if the enum does not have a raw type

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

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)
        }

    }
}

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

但是,我无法将父结构中的涂装映射到此枚举,我想知道我该怎么做?

...

我想我也必须对这个结构实施 init(from decoder: Decoder)encode(to encoder: Encoder) -- 特别是如果我想在将来将我的数据保存到 JSON ;但我不确定。

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

谢谢

问题是您 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
    }
}

你可以大大简化你的代码,你只需要下面的代码。通过说你的枚举是 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
}