Heterogene JSON decoderen
Verwerk polymorfe en dynamische JSON-structuren.
Heterogene JSON decoderen is een gratis Swift Academy-les op CoddyKit. Dit is les 4 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Swift Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Swift Academy bevat in totaal 4 lessen.
Wat is heterogene JSON?
Sommige API's retourneren lijsten waarin objecten verschillende structuren hebben, herkenbaar aan een type-veld. Om deze naar één Swift-type te decoderen, moet je die aanduiding eerst inspecteren.
import Foundation
let json = "[{\"type\":\"text\",\"value\":\"hi\"},{\"type\":\"number\",\"value\":42}]"
print("Each element carries a type discriminator")Modelleren met een enumeratie
Een natuurlijk Swift-model is een enumeratie met gekoppelde waarden — één geval per JSON-structuur. De decoder kiest het geval op basis van de aanduiding.
import Foundation
enum Block {
case text(String)
case number(Int)
}
print("Enum models the variants")De sleutel voor de aanduiding definiëren
Voeg een CodingKeys-enumeratie toe met het veld voor de aanduiding (hier type) en de sleutels van de inhoud die je moet lezen.
import Foundation
enum CodingKeys: String, CodingKey {
case type
case value
}
print(CodingKeys.type.stringValue, CodingKeys.value.stringValue)De aanduiding lezen
Decodeer in init(from:) eerst de tekenreeks type en schakel vervolgens op basis daarvan om de bijbehorende inhoud te decoderen.
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) }Een gemengde lijst decoderen
Zodra de enumeratie Decodable is, verwerkt het decoderen van [Block].self een volledige lijst met verschillende structuren in één aanroep.
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)Het resultaat met patronen vergelijken
Na het decoderen loop je de enumeratiegevallen langs om elke variant op typeveilige wijze af te handelen.
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)
}
}Geneste inhoud
Wanneer varianten rijkere gegevens bevatten, decodeer je voor elk geval een geneste Codable-structuur in plaats van één enkele waarde.
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)
}Onbekende typen netjes afhandelen
In plaats van fouten te veroorzaken bij onbekende aanduidingen, kun je ze aan een terugvalgeval koppelen, zodat nieuwe typen op de server de client nooit laten crashen.
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") }Een goede aanduiding kiezen
De aanduiding moet een stabiel, verplicht veld zijn. Een String-enumeratie met bekende typennamen houdt de afhandeling volledig en leesbaar.
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)Polymorfe waarden coderen
Om heen-en-terugcodering mogelijk te maken, implementeer je ook encode(to:): schrijf de aanduiding en de inhoud van de variant weer weg.
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 samenvoegen
Een volledig polymorf model decodeert een gemengde lijst, handelt elke variant af en kan dezelfde structuur weer coderen — een robuust patroon voor flexibele API's.
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)Korte toets: heterogene JSON
Toets je begrip van polymorfe decodering.
Samenvatting: heterogene JSON decoderen
Je hebt geleerd hoe je polymorfe inhoud afhandelt:
- Modelleer varianten als een enumeratie met gekoppelde waarden.
- Decodeer in
init(from:)het veld met de aanduiding en schakel daarna om het juiste geval op te bouwen. - Decodeer gemengde lijsten met
[Enum].selfen vergelijk de resultaten met patronen. - Voeg een terugvalgeval toe voor onbekende typen en implementeer
encode(to:)voor heen-en-terugcodering.
Leer Swift met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 122
- Lessen
- 409
Veelgestelde vragen
Is de les “Heterogene JSON decoderen” gratis?
Ja — je kunt hier op het web alle 3 lessen van het leerpad Swift Academy, waaronder “Heterogene JSON decoderen”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus Swift Academy bevat in totaal 4 lessen.
Wat leer ik in “Heterogene JSON decoderen”?
Verwerk polymorfe en dynamische JSON-structuren. Je oefent met Swift Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Swift Academy te beginnen?
Ervaring vooraf is niet nodig. Swift Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 4 van 4.
Hoe lang duurt de les “Heterogene JSON decoderen”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Swift Academy?
Ja. Elke les over Swift Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- CodingKeys voor hernoemen
- Strategieën voor key- en datedecodering
- Handmatige encode(to:) en init(from:)
- Heterogene JSON decoderen