具有多个键和关联值的可编码枚举

时间:2019-08-25 07:13:51

标签: swift enums codable

我已经看到了在所有个案都有关联值时如何使枚举符合Codable的答案,但是我不清楚如何混合具有和不具有关联值的个案的枚举:

???如何在给定的情况下使用同一键的多个变体?

???如何编码/解码没有关联值的案件?

enum EmployeeClassification : Codable, Equatable {

case aaa
case bbb
case ccc(Int) // (year)

init?(rawValue: String?) {
    guard let val = rawValue?.lowercased() else {
        return nil
    }
    switch val {
        case "aaa", "a":
            self = .aaa
        case "bbb":
            self = .bbb
        case "ccc":
            self = .ccc(0)
        default: return nil
    }
}

// Codable
private enum CodingKeys: String, CodingKey {
    case aaa // ??? how can I accept "aaa", "AAA", and "a"?
    case bbb
    case ccc
}

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    if let value = try? container.decode(Int.self, forKey: .ccc) {
        self = .ccc(value)
        return
    }
    // ???
    // How do I decode the cases with no associated value?
}
func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    switch self {
    case .ccc(let year):
        try container.encode(year, forKey: .ccc)
    default:
        // ???
        // How do I encode cases with no associated value?
    }
}
}

1 个答案:

答案 0 :(得分:1)

使用init方法假定的原始字符串值作为枚举大小写的(字符串)值

enum EmployeeClassification : Codable, Equatable {

    case aaa
    case bbb
    case ccc(Int) // (year)

    init?(rawValue: String?) {
        guard let val = rawValue?.lowercased() else {
            return nil
        }
        switch val {
        case "aaa", "a":
            self = .aaa
        case "bbb":
            self = .bbb
        case "ccc":
            self = .ccc(0)
        default: return nil
        }
    }

    // Codable
    private enum CodingKeys: String, CodingKey { case aaa, bbb, ccc }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        if let value = try? container.decode(Int.self, forKey: .ccc) {
            self = .ccc(value)
        } else if let aaaValue = try? container.decode(String.self, forKey: .aaa), ["aaa", "AAA", "a"].contains(aaaValue) {
            self = .aaa
        } else if let bbbValue = try? container.decode(String.self, forKey: .bbb), bbbValue == "bbb" {
            self = .bbb
        } else {
            throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: container.codingPath, debugDescription: "Data doesn't match"))
        }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        switch self {
        case .aaa: try container.encode("aaa", forKey: .aaa)
        case .bbb: try container.encode("bbb", forKey: .bbb)
        case .ccc(let year): try container.encode(year, forKey: .ccc)
        }
    }
}

解码错误非常普遍。您可以为每个CodingKey抛出更具体的错误