Я немного запутался при использовании 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: ()
}
}
}