0Pricing
Swift Academy · Lektion

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].self und 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

  1. CodingKeys zum Umbenennen
  2. Strategien für Schlüssel- und Datumsdecodierung
  3. Manuelles encode(to:) und init(from:)
  4. Heterogenes JSON decodieren
← Zurück zu Swift Academy