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]