Кодируемое соответствие для вложенного Enum? - PullRequest
0 голосов
/ 30 октября 2019

Я немного запутался при использовании Codable с вложенными перечислениями. Предположим, у меня есть следующее перечисление:

enum ItemStatus {
    enum Foo {
        case a
        case b(Double, Double)
        case c
    }
    enum Bar {
        case x(String)
        case y
        case z(Int)
    }
}
extension ItemStatus: Codable {
    init(from decoder: Decoder) throws {
    }
    func encode(to encoder: Encoder) throws {
    }
}

Для нормальных перечислений я реализую Codable следующим образом. Это работает, но я не уверен, как реализовать Codable для перечисления верхнего уровня (в данном случае ItemStats), и моя интуиция говорит мне, что есть более эффективный способ написать это в любом случае:

extension ItemStatus.Bar {
    init?(rawValue: String?) {
        guard let val = rawValue?.lowercased() else {
            return nil
        }
        switch val {
        case "x": self = .x("")
        case "y": self = .y
        case "z": self = .z(0)
        default: return nil
        }
    }
    private var typeStr: String {
        guard let label = Mirror(reflecting: self).children.first?.label else {
            return .init(describing: self)
        }
        return label
    }
}
extension ItemStatus.Bar : Codable {
    private enum CodingKeys: String, CodingKey {
        case type
        case xVal
        case zVal
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        guard let type = try? container.decode(String.self, forKey: .type) else {
            throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: container.codingPath, debugDescription: "Could not get type of Bar."))
        }
        guard let base = ItemStatus.Bar(rawValue: type) else {
            throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: container.codingPath, debugDescription: "Could not init Bar with value: \(type)"))
        }
        switch base {
        case .x:
            let val = try container.decode(String.self, forKey: .xVal)
            self = .x(val)
        case .z:
            let val = try container.decode(Int.self, forKey: .zVal)
            self = .z(val)
        default:
            self = base
        }
    }
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(self.typeStr, forKey: .type)
        switch self {
        case .x(let val):
            try container.encode(val, forKey: .xVal)
        case .z(let val):
            try container.encode(val, forKey: .zVal)
        default: ()
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...