Декодирование неизвестных кодируемых значений перечисления по умолчанию
Я должен десериализовать строку JSON следующим образом:
{ "name" : "John Smith", "value" : "someValue" }
В Swift 4, где "значение" должно быть перечислением, а весь объект-структурой, подобной:
struct MyType {
name: String?
value: Value?
}
В какой-то момент в будущем, возможно, будут добавлены новые значения enum в бэкэнде, поэтому я подумал, что было бы разумно иметь некоторый запасной вариант.
Я думал, что смогу создать перечисление, подобное
enum Value {
case someValue
case someOtherValue
case unknown(value: String)
}
Но я просто не могу понять, как десериализовать это перечисление и заставить его работать. Ранее я просто использовал перечисление String
, но десериализация неизвестных значений приводит к ошибкам.
Есть ли простой способ заставить это работать или я должен десериализовать значение как String
и создать пользовательский геттер в структуре с оператором switch, чтобы вернуть один из случаев (вероятно, даже не в самой структуре, а в моей модели представления)?
1 ответ:
Можно реализовать
init(from decoder: Decoder)
иencode(to encoder: Encoder)
и обрабатывать каждый случай явно, т. е.struct MyType: Codable { var name: String? var value: Value? enum CodingKeys: String, CodingKey { case name case value } init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) name = try values.decode(String.self, forKey: .name) let strValue = try values.decode(String.self, forKey: .value) //You need to handle every case explicitly switch strValue { case "someValue": value = Value.someValue case "someOtherValue": value = Value.someOtherValue default: value = Value.unknown(value: strValue) } } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(name, forKey: .name) if let val = value { //You need to handle every case explicitly switch val { case .someValue, .someOtherValue: try container.encode(String(describing: val), forKey: .value) case .unknown(let strValue): try container.encode(strValue, forKey: .value) } } } } enum Value { case someValue case someOtherValue case unknown(value: String) }