Dekoding av heterogen JSON
Håndter polymorfe og dynamiske JSON-strukturer.
Dekoding av heterogen JSON er en gratis leksjon i Swift Academy på CoddyKit. Dette er leksjon 4 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Swift Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Swift Academy inneholder totalt 4 leksjoner.
Hva er heterogen JSON?
Noen API-er returnerer arrayer der objektene har ulike strukturer, identifisert av et type-felt. For å dekode disse til én Swift-type må du først undersøke denne diskriminatoren.
import Foundation
let json = "[{\"type\":\"text\",\"value\":\"hi\"},{\"type\":\"number\",\"value\":42}]"
print("Each element carries a type discriminator")Modellere med en enum
En naturlig Swift-modell er en enum med tilknyttede verdier – én case for hver JSON-struktur. Dekoderen velger riktig case basert på diskriminatoren.
import Foundation
enum Block {
case text(String)
case number(Int)
}
print("Enum models the variants")Definere diskriminatornøkkelen
Legg til en CodingKeys-enum som inneholder diskriminatorfeltet (her type) samt payload-nøklene du trenger å lese.
import Foundation
enum CodingKeys: String, CodingKey {
case type
case value
}
print(CodingKeys.type.stringValue, CodingKeys.value.stringValue)Lese diskriminatoren
I init(from:) dekoder du først type-strengen og bruker deretter en switch på den for å dekode den samsvarende payloaden.
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) }Dekode en blandet array
Når enum-en er Decodable, håndterer dekoding av [Block].self en hel array med blandede strukturer i ett kall.
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)Mønstergjenkjenne resultatet
Etter dekodingen kan du bruke switch på enum-en for å håndtere hver variant på en typesikker måte.
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)
}
}Nestede payloader
Når variantene inneholder mer omfattende data, dekoder du en nestet Codable-struktur for hvert case i stedet for én enkelt verdi.
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)
}Håndtere ukjente typer på en robust måte
I stedet for å kaste en feil for ukjente diskriminatorer kan du tilordne dem til en reserve-case, slik at nye servertyper aldri får klienten til å krasje.
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") }Velge en god diskriminator
Diskriminatoren bør være et stabilt og obligatorisk felt. En String-enum med kjente typenavn gjør switch-uttrykket uttømmende og lett å lese.
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)Kode polymorfe verdier
For å kunne gjøre en tur-retur-konvertering implementerer du også encode(to:): skriv diskriminatoren og variantens payload tilbake.
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)!)Sette alt sammen
En fullstendig polymorf modell dekoder en blandet array, bruker switch på hver variant og kan kode tilbake til den samme strukturen – et robust mønster for fleksible API-er.
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)Kort kontroll: Heterogen JSON
Test forståelsen din av polymorf dekoding.
Oppsummering: Dekoding av heterogen JSON
Du har lært å håndtere polymorfe payloader:
- Modeller varianter som en enum med tilknyttede verdier.
- I
init(from:)dekoder du diskriminatorfeltet og bruker deretter switch for å bygge riktig case. - Dekoder blandede arrayer med
[Enum].self, og mønstergjenkjenn resultatene. - Legg til en reserve-case for ukjente typer, og implementer
encode(to:)for å kunne gjøre en tur-retur-konvertering.
Lær deg Swift med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 122
- Leksjoner
- 409
Ofte stilte spørsmål
Er leksjonen «Dekoding av heterogen JSON» gratis?
Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Swift Academy, inkludert «Dekoding av heterogen JSON», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Swift Academy inneholder totalt 4 leksjoner.
Hva lærer jeg i «Dekoding av heterogen JSON»?
Håndter polymorfe og dynamiske JSON-strukturer. Du øver på Swift Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med Swift Academy?
Ingen tidligere erfaring er nødvendig. Swift Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.
Hvor lang tid tar leksjonen «Dekoding av heterogen JSON»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne Swift Academy-leksjonen?
Ja. Alle Swift Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- CodingKeys for navneendring
- Strategier for nøkkel- og datodekoding
- Manuell encode(to:) og init(from:)
- Dekoding av heterogen JSON