Swift Language Serializzazione, codifica e decodifica JSON con Apple Foundation e Swift Standard Library


Esempio

La classe JSONSerialization è integrata nel framework Foundation di Apple.

2.2

Leggi JSON

La funzione JSONObjectWithData prende NSData e restituisce AnyObject . Puoi usare as? per convertire il risultato nel tipo atteso.

do {
    guard let jsonData = "[\"Hello\", \"JSON\"]".dataUsingEncoding(NSUTF8StringEncoding) else {
        fatalError("couldn't encode string as UTF-8")
    }

    // Convert JSON from NSData to AnyObject
    let jsonObject = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
    
    // Try to convert AnyObject to array of strings
    if let stringArray = jsonObject as? [String] {
        print("Got array of strings: \(stringArray.joinWithSeparator(", "))")
    }
} catch {
    print("error reading JSON: \(error)")
}

Puoi passare le options: .AllowFragments invece delle options: [] per consentire la lettura di JSON quando l'oggetto di livello superiore non è un array o un dizionario.

Scrivi JSON

Chiamando dataWithJSONObject converte un oggetto compatibile con JSON (array nidificati o dizionari con stringhe, numeri e NSNull ) su NSData raw codificato come UTF-8.

do {
    // Convert object to JSON as NSData
    let jsonData = try NSJSONSerialization.dataWithJSONObject(jsonObject, options: [])
    print("JSON data: \(jsonData)")
    
    // Convert NSData to String
    let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding)!
    print("JSON string: \(jsonString)")
} catch {
    print("error writing JSON: \(error)")
}

È possibile passare options: .PrettyPrinted anziché options: [] per la stampa carina.

3.0

Stesso comportamento in Swift 3 ma con una sintassi diversa.

do {
    guard let jsonData = "[\"Hello\", \"JSON\"]".data(using: String.Encoding.utf8) else {
        fatalError("couldn't encode string as UTF-8")
    }
    
    // Convert JSON from NSData to AnyObject
    let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: [])
    
    // Try to convert AnyObject to array of strings
    if let stringArray = jsonObject as? [String] {
        print("Got array of strings: \(stringArray.joined(separator: ", "))")
    }
} catch {
    print("error reading JSON: \(error)")
}

do {
    // Convert object to JSON as NSData
    let jsonData = try JSONSerialization.data(withJSONObject: jsonObject, options: [])
    print("JSON data: \(jsonData)")

    // Convert NSData to String
    let jsonString = String(data: jsonData, encoding: .utf8)!
    print("JSON string: \(jsonString)")
} catch {
    print("error writing JSON: \(error)")
}

Nota: il seguente è attualmente disponibile solo in Swift 4.0 e versioni successive.

A partire da Swift 4.0, la libreria standard di Swift include i protocolli Encodable e Decodable per definire un approccio standardizzato alla codifica e alla decodifica dei dati. L'adozione di questi protocolli consentirà implementazioni dei protocolli Encoder e Decoder prendere i dati e codificarli o decodificarli da e verso una rappresentazione esterna come JSON. La conformità al protocollo Codable combina entrambi i protocolli Encodable e Decodable . Questo è ora il mezzo raccomandato per gestire JSON nel tuo programma.

Codifica e decodifica automaticamente

Il modo più semplice per rendere un tipo codificabile è dichiarare le sue proprietà come tipi già Codable . Questi tipi includono tipi di libreria standard come String , Int e Double ; e tipi di base come Date , Data e URL . Se le proprietà di un tipo sono codificabili, il tipo stesso si conformerà automaticamente a Codable semplicemente dichiarando la conformità.

Si consideri il seguente esempio, in cui la struttura del Book è conforme al Codable .

struct Book: Codable {
    let title: String
    let authors: [String]
    let publicationDate: Date
}

Nota che le raccolte standard come Array e Dictionary conformi a Codable se contengono tipi codificabili.

Adottando Codable , la struttura del Book può ora essere codificata e decodificata da JSON utilizzando le classi di Apple Foundation JSONEncoder e JSONDecoder , anche se Book stesso non contiene codice per gestire specificamente JSON. Anche i codificatori e decodificatori personalizzati possono essere scritti, rispettando i protocolli Encoder e Decoder , rispettivamente.

Codifica dati JSON

// Create an instance of Book called book
let encoder = JSONEncoder()
let data = try! encoder.encode(book) // Do not use try! in production code
print(data)

Imposta encoder.outputFormatting = .prettyPrinted per facilitare la lettura. ## Decodifica dai dati JSON

Decodifica dai dati JSON

// Retrieve JSON string from some source
let jsonData = jsonString.data(encoding: .utf8)!
let decoder = JSONDecoder()
let book = try! decoder.decode(Book.self, for: jsonData) // Do not use try! in production code
print(book)

Nell'esempio sopra, Book.self informa il decodificatore del tipo a cui il JSON deve essere decodificato.

Codifica o decodifica in esclusiva

A volte potrebbe non essere necessario che i dati siano entrambi codificabili e decodificabili, ad esempio quando è necessario leggere solo i dati JSON da un'API o se il programma invia solo dati JSON a un'API.

Se si intende solo scrivere dati JSON, conformare il proprio tipo a Encodable .

struct Book: Encodable {
    let title: String
    let authors: [String]
    let publicationDate: Date
}

Se si intende solo leggere i dati JSON, conformare il proprio tipo a Decodable .

struct Book: Decodable {
    let title: String
    let authors: [String]
    let publicationDate: Date
}

Utilizzo dei nomi chiave personalizzati

Le API utilizzano spesso convenzioni di denominazione diverse dal caso cammello standard Swift, ad esempio il caso serpente. Questo può diventare un problema quando si tratta di decodificare JSON, poiché per impostazione predefinita le chiavi JSON devono essere allineate esattamente con i nomi delle proprietà del tipo. Per gestire questi scenari è possibile creare chiavi personalizzate per il proprio tipo utilizzando il protocollo CodingKey .

struct Book: Codable {
    // ...
    enum CodingKeys: String, CodingKey { 
        case title
        case authors
        case publicationDate = "publication_date"
    }
}

CodingKeys vengono generati automaticamente per i tipi che adottano il protocollo Codable , ma creando la nostra implementazione nell'esempio precedente, permettiamo al nostro decodificatore di abbinare la publicationDate caso cammello publicationDate con il caso snake publication_date come viene fornito dall'API.