0Pricing
Swift Academy · Lezione

encode(to:) e init(from:) manuali

Assumi il pieno controllo della logica di serializzazione.

encode(to:) e init(from:) manuali è una lezione Swift Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Swift Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Swift Academy include 4 lezioni in totale.

Quando la sintesi non basta

A volte la struttura JSON non corrisponde alle proprietà: potrebbe essere necessario eseguire trasformazioni calcolate, fornire valori predefiniti o appiattire la struttura. In questi casi, implementate manualmente encode(to:) e init(from:).

import Foundation

struct Temperature: Codable {
    var celsius: Double
}

print("Manual coding gives full control")

Dichiarare prima CodingKeys

La codifica manuale inizia con un'enum CodingKeys. I keyed container usano queste chiavi per leggere e scrivere i valori.

import Foundation

struct User {
    var name: String
    var age: Int
    enum CodingKeys: String, CodingKey {
        case name
        case age
    }
}

print(User.CodingKeys.name.stringValue)

Implementare init(from:)

init(from decoder:) ottiene un keyed container con container(keyedBy:), quindi decodifica ogni proprietà usando la relativa chiave.

import Foundation

struct User: Decodable {
    var name: String
    var age: Int
    enum CodingKeys: String, CodingKey { case name, age }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        name = try c.decode(String.self, forKey: .name)
        age = try c.decode(Int.self, forKey: .age)
    }
}

let u = try JSONDecoder().decode(User.self, from: "{\"name\":\"Ada\",\"age\":36}".data(using: .utf8)!)
print(u.name, u.age)

Implementare encode(to:)

encode(to encoder:) ottiene un keyed container modificabile con container(keyedBy:) e scrive ogni proprietà con encode(_:forKey:).

import Foundation

struct User: Encodable {
    var name: String
    var age: Int
    enum CodingKeys: String, CodingKey { case name, age }
    func encode(to encoder: Encoder) throws {
        var c = encoder.container(keyedBy: CodingKeys.self)
        try c.encode(name, forKey: .name)
        try c.encode(age, forKey: .age)
    }
}

let data = try JSONEncoder().encode(User(name: "Ada", age: 36))
print(String(data: data, encoding: .utf8)!)

Codable completo manualmente

Implementando entrambi i metodi, il tipo diventa completamente Codable, con una logica personalizzata in entrambe le direzioni.

import Foundation

struct Point: Codable {
    var x: Int
    var y: Int
    enum CodingKeys: String, CodingKey { case x, y }
    init(x: Int, y: Int) { self.x = x; self.y = y }
    init(from d: Decoder) throws {
        let c = try d.container(keyedBy: CodingKeys.self)
        x = try c.decode(Int.self, forKey: .x)
        y = try c.decode(Int.self, forKey: .y)
    }
    func encode(to e: Encoder) throws {
        var c = e.container(keyedBy: CodingKeys.self)
        try c.encode(x, forKey: .x)
        try c.encode(y, forKey: .y)
    }
}

let back = try JSONDecoder().decode(Point.self, from: try JSONEncoder().encode(Point(x: 1, y: 2)))
print(back.x, back.y)

Fornire valori predefiniti

Usate decodeIfPresent con l'operatore di coalescenza dei valori nulli per fornire un valore predefinito quando manca una chiave, invece di generare un errore.

import Foundation

struct Settings: Decodable {
    var theme: String
    enum CodingKeys: String, CodingKey { case theme }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        theme = try c.decodeIfPresent(String.self, forKey: .theme) ?? "light"
    }
}

let s = try JSONDecoder().decode(Settings.self, from: "{}".data(using: .utf8)!)
print(s.theme)

Trasformare i valori

La decodifica manuale consente di trasformare il JSON grezzo in una rappresentazione più ricca: in questo caso, un valore in Fahrenheit viene memorizzato in Celsius.

import Foundation

struct Reading: Decodable {
    var celsius: Double
    enum CodingKeys: String, CodingKey { case fahrenheit }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        let f = try c.decode(Double.self, forKey: .fahrenheit)
        celsius = (f - 32) * 5 / 9
    }
}

let r = try JSONDecoder().decode(Reading.self, from: "{\"fahrenheit\":212}".data(using: .utf8)!)
print(r.celsius)

Appiattire il JSON annidato

È possibile leggere un container annidato con nestedContainer(keyedBy:forKey:) e portare i suoi valori al livello di una struct Swift piatta.

import Foundation

struct Profile: Decodable {
    var city: String
    enum Keys: String, CodingKey { case address }
    enum AddressKeys: String, CodingKey { case city }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: Keys.self)
        let a = try c.nestedContainer(keyedBy: AddressKeys.self, forKey: .address)
        city = try a.decode(String.self, forKey: .city)
    }
}

let json = "{\"address\":{\"city\":\"Rome\"}}"
let p = try JSONDecoder().decode(Profile.self, from: json.data(using: .utf8)!)
print(p.city)

Codificare in un container annidato

La codifica può eseguire l'operazione inversa: scrivere una struct piatta come oggetto JSON annidato usando nestedContainer(keyedBy:forKey:).

import Foundation

struct Profile: Encodable {
    var city: String
    enum Keys: String, CodingKey { case address }
    enum AddressKeys: String, CodingKey { case city }
    func encode(to encoder: Encoder) throws {
        var c = encoder.container(keyedBy: Keys.self)
        var a = c.nestedContainer(keyedBy: AddressKeys.self, forKey: .address)
        try a.encode(city, forKey: .city)
    }
}

let data = try JSONEncoder().encode(Profile(city: "Rome"))
print(String(data: data, encoding: .utf8)!)

Convalidare durante la decodifica

Poiché init(from:) è semplicemente un inizializzatore, è possibile convalidare i valori e generare un errore personalizzato quando non rientrano nell'intervallo consentito.

import Foundation

struct Score: Decodable {
    var value: Int
    enum CodingKeys: String, CodingKey { case value }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        let v = try c.decode(Int.self, forKey: .value)
        guard (0...100).contains(v) else {
            throw DecodingError.dataCorruptedError(forKey: .value, in: c, debugDescription: "out of range")
        }
        value = v
    }
}

let s = try JSONDecoder().decode(Score.self, from: "{\"value\":80}".data(using: .utf8)!)
print(s.value)

Combinare metodi manuali e sintetizzati

Un tipo può implementare manualmente un solo metodo e lasciare che il compilatore sintetizzi l'altro, ad esempio usando un init(from:) personalizzato con la codifica sintetizzata.

import Foundation

struct Flag: Codable {
    var on: Bool
    enum CodingKeys: String, CodingKey { case on }
    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        on = (try? c.decode(Bool.self, forKey: .on)) ?? false
    }
    init(on: Bool) { self.on = on }
}

let data = try JSONEncoder().encode(Flag(on: true))
print(String(data: data, encoding: .utf8)!)

Verifica rapida: codifica manuale

Verificate la vostra comprensione dei metodi Codable scritti manualmente.

Riepilogo: encode(to:) e init(from:) manuali

Avete imparato ad avere il pieno controllo della codifica:

  • Dichiarate CodingKeys, quindi implementate init(from:) e encode(to:).
  • Usate container(keyedBy:) e encode/decode(_:forKey:).
  • decodeIfPresent insieme a ?? fornisce valori predefiniti; nestedContainer appiattisce o annida il JSON.
  • È possibile convalidare e trasformare i valori, oltre a combinare metodi manuali e sintetizzati.

Domande Frequenti

La lezione «encode(to:) e init(from:) manuali» è gratuita?

Sì — il testo completo di «encode(to:) e init(from:) manuali» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Swift Academy, passa a CoddyKit PRO. Il corso Swift Academy include 4 lezioni in totale.

Cosa imparerò in «encode(to:) e init(from:) manuali»?

Assumi il pieno controllo della logica di serializzazione. Eserciti Swift Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Swift Academy?

Non è richiesta alcuna esperienza precedente. Swift Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «encode(to:) e init(from:) manuali»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Swift Academy?

Sì. Ogni lezione Swift Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. CodingKeys per rinominare
  2. Strategie di decodifica per chiavi e date
  3. encode(to:) e init(from:) manuali
  4. Decodifica di JSON eterogenei
← Torna a Swift Academy