Swift Decodable - как избежать универсального типа?
Я получаю сложный вложенный объект из своего JSON REST API.
DocumentDraft
- uuid: String
- schema: Schema // Very complicated object with many variations
- url: String
- values: [Value]
- successors: [String]
- predecessors: [String]
Value
- key: String
- val: String? OR [String]? // <-- This is the problem
Я полагаю, что правильный способ справиться с этим - ввести общий тип.
struct Value<V: Decodable>: Decodable {
let key: String
let val: V?
}
... но даже в этом случае это values
может быть смешанный массив, поэтому я не понимаю, как объявление того, что это V
такое, может помочь.
Но затем, конечно же, общий тип распространяется вверх по иерархии, к DocumentDraft
объекту, к издателю, к моим вызовам API и т. Д., Загрязняя всю цепочку очень чистых и удобочитаемых вызовов и объектов. Я хотел бы разобраться с этим только на уровне Value
, и пусть JSONDecoder просто каким-то образом вернет один из двух.
Есть еще один способ борьбы с этими двумя возможностями Факультативного val
либо как String
или [String]
без изменения всей родительского объекта?
Ответы
Вы можете добиться этого, используя только [String]
тип и вручную реализовав init(from:)
функцию Decodable
протокола следующим образом:
struct Value: Decodable {
let key: String
let val: [String]?
enum CodingKeys: String, CodingKey {
case key, val
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
key = try container.decode(String.self, forKey: .key)
do {
if let string = try container.decodeIfPresent(String.self, forKey: .val) {
val = [string]
} else {
val = nil
}
} catch DecodingError.typeMismatch {
val = try container.decodeIfPresent([String].self, forKey: .val)
}
}
}
При успешном декодировании в String
значение создайте массив строк только с одним элементом. Когда декодирование в String
значение не удается, попробуйте декодировать как[String]