Swift Decodable - bagaimana menghindari tipe generik?
Saya mengambil objek bersarang yang kompleks dari JSON REST API saya.
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
Saya kira cara yang tepat untuk mengatasinya adalah dengan memperkenalkan tipe generik.
struct Value<V: Decodable>: Decodable {
let key: String
let val: V?
}
... tapi meski begitu, values
bisa menjadi array campuran, jadi saya tidak melihat bagaimana menyatakan apa V
yang akan membantu.
Tapi kemudian, tentu saja tipe generik menyebar ke seluruh hierarki, ke DocumentDraft
objek, ke penerbit, ke panggilan API saya, dll. Mencemari seluruh rantai panggilan dan objek yang sangat bersih dan dapat dibaca. Saya ingin menangani ini hanya pada level Value
, dan biarkan JSONDecoder mengembalikan salah satu dari keduanya.
Apakah ada cara lain untuk menangani dua kemungkinan opsional val
sebagai salah satu String
atau [String]
tanpa mengubah seluruh objek induk?
Jawaban
Anda dapat mencapainya hanya dengan menggunakan [String]
tipe dan secara manual mengimplementasikan init(from:)
fungsi Decodable
protokol seperti ini:
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)
}
}
}
Ketika decoding ke String
nilai berhasil, buat array string hanya dengan satu elemen. Ketika decoding ke String
nilai gagal, coba decode sebagai[String]