Heterogenes JSON decodieren
Verarbeiten Sie polymorphe und dynamische JSON-Strukturen.
Heterogenes JSON decodieren ist eine kostenlose Swift Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Swift Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Swift Academy-Kurs umfasst insgesamt 4 Lektionen.
Was ist heterogenes JSON?
Manche APIs liefern Arrays, deren Objekte unterschiedliche Strukturen haben und durch ein type-Feld unterschieden werden. Um diese in einen einzigen Swift-Typ zu dekodieren, müssen Sie zuerst diesen Discriminator untersuchen.
import Foundation
let json = "[{\"type\":\"text\",\"value\":\"hi\"},{\"type\":\"number\",\"value\":42}]"
print("Each element carries a type discriminator")Mit einem Enum modellieren
Ein natürliches Swift-Modell ist ein Enum mit zugehörigen Werten – ein Case pro JSON-Struktur. Der Decoder wählt anhand des Discriminators das passende Case aus.
import Foundation
enum Block {
case text(String)
case number(Int)
}
print("Enum models the variants")Den Discriminator-Schlüssel definieren
Fügen Sie ein CodingKeys-Enum hinzu, das neben dem Discriminator-Feld (hier type) auch die benötigten Payload-Schlüssel enthält.
import Foundation
enum CodingKeys: String, CodingKey {
case type
case value
}
print(CodingKeys.type.stringValue, CodingKeys.value.stringValue)Den Discriminator lesen
Dekodieren Sie in init(from:) zuerst die Zeichenfolge type und verwenden Sie anschließend eine switch-Anweisung, um die passende Payload zu dekodieren.
import Foundation
enum Block: Decodable {
case text(String)
case number(Int)
enum CodingKeys: String, CodingKey { case type, value }
init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
let type = try c.decode(String.self, forKey: .type)
switch type {
case "text": self = .text(try c.decode(String.self, forKey: .value))
case "number": self = .number(try c.decode(Int.self, forKey: .value))
default: throw DecodingError.dataCorruptedError(forKey: .type, in: c, debugDescription: "unknown type")
}
}
}
let b = try JSONDecoder().decode(Block.self, from: "{\"type\":\"text\",\"value\":\"hi\"}".data(using: .utf8)!)
if case let .text(s) = b { print(s) }Ein gemischtes Array dekodieren
Sobald das Enum Decodable ist, dekodiert [Block].self ein vollständiges Array mit unterschiedlichen Strukturen in einem einzigen Aufruf.
import Foundation
enum Block: Decodable {
case text(String)
case number(Int)
enum CodingKeys: String, CodingKey { case type, value }
init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
switch try c.decode(String.self, forKey: .type) {
case "text": self = .text(try c.decode(String.self, forKey: .value))
case "number": self = .number(try c.decode(Int.self, forKey: .value))
default: throw DecodingError.dataCorruptedError(forKey: .type, in: c, debugDescription: "unknown")
}
}
}
let json = "[{\"type\":\"text\",\"value\":\"hi\"},{\"type\":\"number\",\"value\":42}]"
let blocks = try JSONDecoder().decode([Block].self, from: json.data(using: .utf8)!)
print(blocks.count)Das Ergebnis per Pattern Matching verarbeiten
Nach dem Dekodieren können Sie mit einer switch-Anweisung über das Enum verzweigen und typsicher auf jede Variante reagieren.
import Foundation
enum Block: Decodable {
case text(String)
case number(Int)
enum CodingKeys: String, CodingKey { case type, value }
init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
switch try c.decode(String.self, forKey: .type) {
case "text": self = .text(try c.decode(String.self, forKey: .value))
case "number": self = .number(try c.decode(Int.self, forKey: .value))
default: throw DecodingError.dataCorruptedError(forKey: .type, in: c, debugDescription: "unknown")
}
}
}
let json = "[{\"type\":\"text\",\"value\":\"hi\"},{\"type\":\"number\",\"value\":42}]"
for b in try JSONDecoder().decode([Block].self, from: json.data(using: .utf8)!) {
switch b {
case .text(let s): print("text:", s)
case .number(let n): print("number:", n)
}
}Verschachtelte Payloads
Wenn Varianten umfangreichere Daten enthalten, dekodieren Sie für jedes Case eine verschachtelte Codable-Struktur statt nur eines einzelnen Werts.
import Foundation
struct ImagePayload: Decodable { var url: String; var width: Int }
enum Block: Decodable {
case image(ImagePayload)
enum CodingKeys: String, CodingKey { case type }
init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
switch try c.decode(String.self, forKey: .type) {
case "image": self = .image(try ImagePayload(from: decoder))
default: throw DecodingError.dataCorruptedError(forKey: .type, in: c, debugDescription: "unknown")
}
}
}
let json = "{\"type\":\"image\",\"url\":\"a.png\",\"width\":100}"
if case let .image(p) = try JSONDecoder().decode(Block.self, from: json.data(using: .utf8)!) {
print(p.url, p.width)
}Unbekannte Typen elegant behandeln
Statt bei unbekannten Discriminators einen Fehler auszulösen, können Sie sie einem Fallback-Case zuordnen. So führen neue Servertypen nie zum Absturz des Clients.
import Foundation
enum Block: Decodable {
case text(String)
case unknown
enum CodingKeys: String, CodingKey { case type, value }
init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
switch try c.decode(String.self, forKey: .type) {
case "text": self = .text(try c.decode(String.self, forKey: .value))
default: self = .unknown
}
}
}
let b = try JSONDecoder().decode(Block.self, from: "{\"type\":\"video\"}".data(using: .utf8)!)
if case .unknown = b { print("fell back to unknown") }Einen guten Discriminator wählen
Der Discriminator sollte ein stabiles, erforderliches Feld sein. Ein String-Enum mit bekannten Typnamen hält die switch-Anweisung vollständig und übersichtlich.
import Foundation
enum Kind: String, Decodable { case text, number }
let data = "\"text\"".data(using: .utf8)!
let k = try JSONDecoder().decode(Kind.self, from: data)
print(k == .text)Polymorphe Werte encodieren
Für eine verlustfreie Hin- und Rückkonvertierung implementieren Sie auch encode(to:): Schreiben Sie den Discriminator zusammen mit der Payload der jeweiligen Variante zurück.
import Foundation
enum Block: Encodable {
case text(String)
case number(Int)
enum CodingKeys: String, CodingKey { case type, value }
func encode(to encoder: Encoder) throws {
var c = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .text(let s):
try c.encode("text", forKey: .type)
try c.encode(s, forKey: .value)
case .number(let n):
try c.encode("number", forKey: .type)
try c.encode(n, forKey: .value)
}
}
}
let data = try JSONEncoder().encode(Block.number(42))
print(String(data: data, encoding: .utf8)!)Alles zusammenführen
Ein vollständiges polymorphes Modell dekodiert ein gemischtes Array, verzweigt je nach Variante und kann dieselbe Struktur wieder encodieren – ein robustes Muster für flexible APIs.
import Foundation
enum Block: Codable {
case text(String)
case number(Int)
enum CodingKeys: String, CodingKey { case type, value }
init(from d: Decoder) throws {
let c = try d.container(keyedBy: CodingKeys.self)
switch try c.decode(String.self, forKey: .type) {
case "text": self = .text(try c.decode(String.self, forKey: .value))
default: self = .number(try c.decode(Int.self, forKey: .value))
}
}
func encode(to e: Encoder) throws {
var c = e.container(keyedBy: CodingKeys.self)
switch self {
case .text(let s): try c.encode("text", forKey: .type); try c.encode(s, forKey: .value)
case .number(let n): try c.encode("number", forKey: .type); try c.encode(n, forKey: .value)
}
}
}
let blocks: [Block] = [.text("hi"), .number(7)]
let data = try JSONEncoder().encode(blocks)
print(try JSONDecoder().decode([Block].self, from: data).count)Kurzer Check: Heterogenes JSON
Testen Sie Ihr Verständnis des polymorphen Dekodierens.
Zusammenfassung: Heterogenes JSON dekodieren
Sie haben gelernt, polymorphe Payloads zu verarbeiten:
- Modellieren Sie Varianten als Enum mit zugehörigen Werten.
- Dekodieren Sie in
init(from:)das Discriminator-Feld und verzweigen Sie dann, um das passende Case zu erstellen. - Dekodieren Sie gemischte Arrays mit
[Enum].selfund verarbeiten Sie die Ergebnisse per Pattern Matching. - Fügen Sie für unbekannte Typen ein Fallback-Case hinzu und implementieren Sie
encode(to:), um die Daten verlustfrei hin- und zurückzukonvertieren.
Häufig gestellte Fragen
Ist die Lektion „Heterogenes JSON decodieren“ kostenlos?
Ja — der vollständige Text von „Heterogenes JSON decodieren“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Swift Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Swift Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Heterogenes JSON decodieren“?
Verarbeiten Sie polymorphe und dynamische JSON-Strukturen. Du übst Swift Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Swift Academy zu starten?
Keine Vorkenntnisse erforderlich. Swift Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Heterogenes JSON decodieren“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Swift Academy-Lektion Code schreiben und ausführen?
Ja. Jede Swift Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- CodingKeys zum Umbenennen
- Strategien für Schlüssel- und Datumsdecodierung
- Manuelles encode(to:) und init(from:)
- Heterogenes JSON decodieren