Analisi corretta di JSON in Swift 3


123

Sto cercando di recuperare una risposta JSON e memorizzare i risultati in una variabile. Ho avuto versioni di questo codice funzionanti nelle versioni precedenti di Swift, fino al rilascio della versione GM di Xcode 8. Ho dato un'occhiata ad alcuni post simili su StackOverflow: Swift 2 Parsing JSON - Impossibile inserire un valore di tipo "AnyObject" e JSON Parsing in Swift 3 .

Tuttavia, sembra che le idee trasmesse lì non si applichino a questo scenario.

Come posso analizzare correttamente la risposta JSON in Swift 3? Qualcosa è cambiato nel modo in cui JSON viene letto in Swift 3?

Di seguito è riportato il codice in questione (può essere eseguito in un playground):

import Cocoa

let url = "https://api.forecast.io/forecast/apiKey/37.5673776,122.048951"

if let url = NSURL(string: url) {
    if let data = try? Data(contentsOf: url as URL) {
        do {
            let parsedData = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments)

        //Store response in NSDictionary for easy access
        let dict = parsedData as? NSDictionary

        let currentConditions = "\(dict!["currently"]!)"

        //This produces an error, Type 'Any' has no subscript members
        let currentTemperatureF = ("\(dict!["currently"]!["temperature"]!!)" as NSString).doubleValue

            //Display all current conditions from API
            print(currentConditions)

            //Output the current temperature in Fahrenheit
            print(currentTemperatureF)

        }
        //else throw an error detailing what went wrong
        catch let error as NSError {
            print("Details of JSON parsing error:\n \(error)")
        }
    }
}

Modifica: ecco un esempio dei risultati della chiamata API successivaprint(currentConditions)

["icon": partly-cloudy-night, "precipProbability": 0, "pressure": 1015.39, "humidity": 0.75, "precipIntensity": 0, "windSpeed": 6.04, "summary": Partly Cloudy, "ozone": 321.13, "temperature": 49.45, "dewPoint": 41.75, "apparentTemperature": 47, "windBearing": 332, "cloudCover": 0.28, "time": 1480846460]

Puoi inserire i dati di esempio restituiti dalla tua chiamata API?
Utente

1
Sì, ho appena aggiunto un campione dei risultati stampati dopo la stampa (currentConditions). Spero che sia d'aiuto.
user2563039

JSON Parse in swift4 utilizzando codificabile protocollo stackoverflow.com/a/52931265/9316566
Naser Mohamed

Risposte:


172

Prima di tutto non caricare mai i dati in modo sincrono da un URL remoto , usa sempre metodi asincroni come URLSession.

"Qualsiasi" non ha membri in pedice

si verifica perché il compilatore non ha idea di quale tipo siano gli oggetti intermedi (ad esempio currentlyin ["currently"]!["temperature"]) e poiché si utilizzano tipi di raccolta Foundation come NSDictionaryil compilatore non ha idea del tipo.

Inoltre in Swift 3 è necessario informare il compilatore sul tipo di tutti gli oggetti sottoscritti.

Devi eseguire il cast del risultato della serializzazione JSON sul tipo effettivo.

Questo codice utilizza URLSessione esclusivamente Swift tipi nativi

let urlString = "https://api.forecast.io/forecast/apiKey/37.5673776,122.048951"

let url = URL(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
  if error != nil {
    print(error)
  } else {
    do {

      let parsedData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
      let currentConditions = parsedData["currently"] as! [String:Any]

      print(currentConditions)

      let currentTemperatureF = currentConditions["temperature"] as! Double
      print(currentTemperatureF)
    } catch let error as NSError {
      print(error)
    }
  }

}.resume()

Per stampare tutte le coppie chiave / valore di currentConditionste potresti scrivere

 let currentConditions = parsedData["currently"] as! [String:Any]

  for (key, value) in currentConditions {
    print("\(key) - \(value) ")
  }

Una nota riguardante jsonObject(with data:

Molti tutorial (sembrano tutti) suggeriscono .mutableContainerso .mutableLeavesopzioni che non hanno alcun senso in Swift. Le due opzioni sono opzioni legacy Objective-C per assegnare il risultato agli NSMutable...oggetti. In Swift, qualsiasi variable è modificabile per impostazione predefinita e passare una qualsiasi di queste opzioni e assegnare il risultato a una letcostante non ha alcun effetto. Inoltre, la maggior parte delle implementazioni non modifica mai comunque il JSON deserializzato.

L'unico (raro) opzione che è utile in Swift è .allowFragmentsche è necessario se se l'oggetto principale JSON potrebbe essere un tipo di valore ( String, Number, Boolo null) piuttosto che uno dei tipi di raccolta ( arrayo dictionary). Ma normalmente ometti il optionsparametro che significa Nessuna opzione .

================================================== =========================

Alcune considerazioni generali per analizzare JSON

JSON è un formato di testo ben organizzato. È molto facile leggere una stringa JSON. Leggi attentamente la stringa . Esistono solo sei tipi diversi: due tipi di raccolta e quattro tipi di valore.


I tipi di raccolta sono

  • Array - JSON: oggetti tra parentesi quadre []- Swift: [Any]ma nella maggior parte dei casi[[String:Any]]
  • Dizionario - JSON: oggetti tra parentesi graffe {}- Swift:[String:Any]

I tipi di valore sono

  • String - JSON: qualsiasi valore tra virgolette doppie "Foo", pari "123"o "false"- Swift:String
  • Number - JSON: valori numerici non tra virgolette 123o 123.0- Swift: IntoDouble
  • Bool - JSON: trueo false non tra virgolette doppie - Swift: trueofalse
  • null - JSON: null- Swift:NSNull

Secondo la specifica JSON, tutte le chiavi nei dizionari devono essere String.


Fondamentalmente si consiglia sempre di utilizzare attacchi opzionali per scartare gli optional in modo sicuro

Se l'oggetto radice è un dictionary ( {}), esegui il cast del tipo a[String:Any]

if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [String:Any] { ...

e recuperare i valori tramite chiavi con ( OneOfSupportedJSONTypesè una raccolta JSON o un tipo di valore come descritto sopra).

if let foo = parsedData["foo"] as? OneOfSupportedJSONTypes {
    print(foo)
} 

Se l'oggetto radice è un array ( []), esegue il cast del tipo a[[String:Any]]

if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]] { ...

e scorrere l'array con

for item in parsedData {
    print(item)
}

Se hai bisogno di un elemento in un indice specifico, controlla anche se l'indice esiste

if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]], parsedData.count > 2,
   let item = parsedData[2] as? OneOfSupportedJSONTypes {
      print(item)
    }
}

Nel raro caso in cui JSON sia semplicemente uno dei tipi di valore, piuttosto che un tipo di raccolta, è necessario passare l' .allowFragmentsopzione e trasmettere il risultato al tipo di valore appropriato, ad esempio

if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String { ...

Apple ha pubblicato un articolo completo nel blog Swift: Working with JSON in Swift


================================================== =========================

In Swift 4+ il Codableprotocollo fornisce un modo più conveniente per analizzare JSON direttamente in strutture / classi.

Ad esempio il dato campione JSON nella domanda (leggermente modificato)

let jsonString = """
{"icon": "partly-cloudy-night", "precipProbability": 0, "pressure": 1015.39, "humidity": 0.75, "precip_intensity": 0, "wind_speed": 6.04, "summary": "Partly Cloudy", "ozone": 321.13, "temperature": 49.45, "dew_point": 41.75, "apparent_temperature": 47, "wind_bearing": 332, "cloud_cover": 0.28, "time": 1480846460}
"""

può essere decodificato nella struttura Weather. I tipi Swift sono gli stessi descritti sopra. Ci sono alcune opzioni aggiuntive:

  • Le stringhe che rappresentano un URLpossono essere decodificate direttamente come URL.
  • L' timeintero può essere decodificato come Datecon il dateDecodingStrategy .secondsSince1970.
  • Le chiavi JSON snaked_cased possono essere convertite in camelCase con l' estensionekeyDecodingStrategy .convertFromSnakeCase

struct Weather: Decodable {
    let icon, summary: String
    let pressure: Double, humidity, windSpeed : Double
    let ozone, temperature, dewPoint, cloudCover: Double
    let precipProbability, precipIntensity, apparentTemperature, windBearing : Int
    let time: Date
}

let data = Data(jsonString.utf8)
do {
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .secondsSince1970
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let result = try decoder.decode(Weather.self, from: data)
    print(result)
} catch {
    print(error)
}

Altre fonti codificabili:


Questo è molto utile. Sono solo curioso del motivo per cui il codice sopra non mostra l'output visibile quando viene eseguito in un parco giochi.
user2563039

Come accennato in precedenza, è necessario eseguire il cast del risultato ambiguo di dict!["currently"]!in un dizionario che il compilatore può dedurre in modo sicuro dalla successiva sottoscrizione della chiave.
vadian

1
L'articolo di Apple è piuttosto interessante, ma per qualche motivo non sono riuscito a farlo funzionare con swift 3. Si lamenta del tipo [String: Any]? non ha membri in pedice. C'erano anche altri problemi con esso, ma sono stato in grado di aggirarli. Qualcuno ha un esempio del proprio codice che funziona effettivamente?
Tonalità

@Shades Fai una domanda e pubblica il tuo codice. Molto probabilmente il tuo problema è correlato agli optional scartati.
vadian

Puoi inserire i dati di esempio restituiti dalla tua chiamata API?
Utente

12

Un grande cambiamento avvenuto con Xcode 8 Beta 6 per Swift 3 è stato che l'ID ora importa come Anyinvece di AnyObject.

Ciò significa che parsedDataviene restituito come un dizionario molto probabilmente con il tipo [Any:Any]. Senza usare un debugger non potrei dirti esattamente cosa NSDictionaryfarà il tuo cast ma l'errore che stai vedendo è perché dict!["currently"]!ha il tipoAny

Quindi, come risolvi questo problema? Dal modo in cui l'hai fatto riferimento, presumo dict!["currently"]!sia un dizionario e quindi hai molte opzioni:

Per prima cosa potresti fare qualcosa del genere:

let currentConditionsDictionary: [String: AnyObject] = dict!["currently"]! as! [String: AnyObject]  

Questo ti darà un oggetto dizionario che puoi quindi interrogare per i valori e così puoi ottenere la tua temperatura in questo modo:

let currentTemperatureF = currentConditionsDictionary["temperature"] as! Double

Oppure se preferisci puoi farlo in linea:

let currentTemperatureF = (dict!["currently"]! as! [String: AnyObject])["temperature"]! as! Double

Spero che questo aiuti, temo di non aver avuto il tempo di scrivere un'app di esempio per testarla.

Un'ultima nota: la cosa più semplice da fare, potrebbe essere semplicemente lanciare il payload JSON [String: AnyObject]all'inizio.

let parsedData = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments) as! Dictionary<String, AnyObject>

dict!["currently"]! as! [String: String]andrà in crash
vadian

Il punto in cui si è schiantato è stata la ["temperatura"] !! e anche cercando di lanciare String su NSString - verificato che la nuova soluzione funzioni swiftlang.ng.bluemix.net/#/repl/57d3bc683a422409bf36c391
discorevilo

[String: String]non può funzionare affatto perché ci sono un paio di valori numerici. Non funziona in un Mac Playground
vadian

@vadian ah, sì, non li avevo notati e la veloce sandbox li nascondeva utilmente! - Corretto [ancora una volta] ora (e testato su macOS). Grazie per averlo fatto notare :)
discorevilo

6
let str = "{\"names\": [\"Bob\", \"Tim\", \"Tina\"]}"

let data = str.data(using: String.Encoding.utf8, allowLossyConversion: false)!

do {
    let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]
    if let names = json["names"] as? [String] 
{
        print(names)
}
} catch let error as NSError {
    print("Failed to load: \(error.localizedDescription)")
}

5

Ho costruito quicktype esattamente per questo scopo. Basta incollare il JSON di esempio e quicktype genera questa gerarchia di tipi per i dati API:

struct Forecast {
    let hourly: Hourly
    let daily: Daily
    let currently: Currently
    let flags: Flags
    let longitude: Double
    let latitude: Double
    let offset: Int
    let timezone: String
}

struct Hourly {
    let icon: String
    let data: [Currently]
    let summary: String
}

struct Daily {
    let icon: String
    let data: [Datum]
    let summary: String
}

struct Datum {
    let precipIntensityMax: Double
    let apparentTemperatureMinTime: Int
    let apparentTemperatureLowTime: Int
    let apparentTemperatureHighTime: Int
    let apparentTemperatureHigh: Double
    let apparentTemperatureLow: Double
    let apparentTemperatureMaxTime: Int
    let apparentTemperatureMax: Double
    let apparentTemperatureMin: Double
    let icon: String
    let dewPoint: Double
    let cloudCover: Double
    let humidity: Double
    let ozone: Double
    let moonPhase: Double
    let precipIntensity: Double
    let temperatureHigh: Double
    let pressure: Double
    let precipProbability: Double
    let precipIntensityMaxTime: Int
    let precipType: String?
    let sunriseTime: Int
    let summary: String
    let sunsetTime: Int
    let temperatureMax: Double
    let time: Int
    let temperatureLow: Double
    let temperatureHighTime: Int
    let temperatureLowTime: Int
    let temperatureMin: Double
    let temperatureMaxTime: Int
    let temperatureMinTime: Int
    let uvIndexTime: Int
    let windGust: Double
    let uvIndex: Int
    let windBearing: Int
    let windGustTime: Int
    let windSpeed: Double
}

struct Currently {
    let precipProbability: Double
    let humidity: Double
    let cloudCover: Double
    let apparentTemperature: Double
    let dewPoint: Double
    let ozone: Double
    let icon: String
    let precipIntensity: Double
    let temperature: Double
    let pressure: Double
    let precipType: String?
    let summary: String
    let uvIndex: Int
    let windGust: Double
    let time: Int
    let windBearing: Int
    let windSpeed: Double
}

struct Flags {
    let sources: [String]
    let isdStations: [String]
    let units: String
}

Genera anche codice di marshalling senza dipendenze per convincere il valore restituito JSONSerialization.jsonObjectin a Forecast, incluso un comodo costruttore che accetta una stringa JSON in modo da poter analizzare rapidamente un Forecastvalore fortemente tipizzato e accedere ai suoi campi:

let forecast = Forecast.from(json: jsonString)!
print(forecast.daily.data[0].windGustTime)

Puoi installare quicktype da npm con npm i -g quicktypeo utilizzare l'interfaccia utente web per ottenere il codice generato completo da incollare nel tuo playground.


I collegamenti stanno fallendo.
ha disegnato ..

Fantastico risparmio di tempo! Buon lavoro!
marko

1
Strumento brillante. Grazie.
Ahmet Ardal

4

Aggiornato il isConnectToNetwork-Functiondopo, grazie a questo post .

Ho scritto un metodo extra per questo:

import SystemConfiguration

func loadingJSON(_ link:String, postString:String, completionHandler: @escaping (_ JSONObject: AnyObject) -> ()) {

    if(isConnectedToNetwork() == false){
        completionHandler("-1" as AnyObject)
        return
    }

    let request = NSMutableURLRequest(url: URL(string: link)!)
    request.httpMethod = "POST"
    request.httpBody = postString.data(using: String.Encoding.utf8)

    let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
        guard error == nil && data != nil else { // check for fundamental networking error
            print("error=\(error)")
            return
        }

        if let httpStatus = response as? HTTPURLResponse , httpStatus.statusCode != 200 { // check for http errors
            print("statusCode should be 200, but is \(httpStatus.statusCode)")
            print("response = \(response)")
        }
        //JSON successfull
        do {
            let parseJSON = try JSONSerialization.jsonObject(with: data!, options: .allowFragments)
            DispatchQueue.main.async(execute: {
                completionHandler(parseJSON as AnyObject)
            });
        } catch let error as NSError {
            print("Failed to load: \(error.localizedDescription)")
        }
    }
    task.resume()
}

func isConnectedToNetwork() -> Bool {

    var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
    zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)

    let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
            SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
        }
    }

    var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
    if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
        return false
    }

    let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
    let ret = (isReachable && !needsConnection)

    return ret
}

Quindi ora puoi chiamarlo facilmente nella tua app dove vuoi

loadingJSON("yourDomain.com/login.php", postString:"email=\(userEmail!)&password=\(password!)") { parseJSON in

    if(String(describing: parseJSON) == "-1"){
        print("No Internet")
    } else {

    if let loginSuccessfull = parseJSON["loginSuccessfull"] as? Bool {
        //... do stuff
    }
}

Marco, quale sarebbe il modo migliore per aggiungere questa funzione nel progetto? in qualsiasi contorller o modello?
KamalPanhwar

hey, aggiungi semplicemente il primo metodo func loadingJSON (...) in un file o una classe extra swift. Dopodiché puoi chiamarlo da ogni controller nel tuo progetto
Marco Weber

L'ho provato, ma mi piace l'idea di dimostrare una soluzione completa e anche come usarla, incluso il metodo helper isConnectedToNetwork () mi è l'idea di come implementarlo probabilmente in un buon codice
Amr Angry

quindi ho appena usato un nuovo file swift (clic sinistro sull'albero del progetto, nuovo file ..., file swift) e l'ho chiamato jsonhelper.swift. in questo file inserisci il primo codice, loadingJSON () e isConnectedToNetwork (). dopodiché puoi usare queste due funzioni in ogni parte del tuo progetto. ad esempio in un loginVC, come azione del pulsante login puoi usare il secondo codice, ovviamente devi cambiare il dominio, la stringa del post e i valori paseJson (parseJSON ["loginSuccessfull"]) in modo che corrispondano a il tuo file php
Marco Weber

0

Swift ha una potente inferenza di tipo. Liberiamoci di "if let" o "guard let" boilerplate e forziamo gli scarti utilizzando un approccio funzionale:

  1. Ecco il nostro JSON. Possiamo usare JSON opzionale o usuale. Sto usando opzionale nel nostro esempio:

    let json: Dictionary<String, Any>? = ["current": ["temperature": 10]]

  1. Funzioni di supporto. Dobbiamo scriverli una sola volta e poi riutilizzarli con qualsiasi dizionario:

    /// Curry
    public func curry<A, B, C>(_ f: @escaping (A, B) -> C) -> (A) -> (B) -> C {
        return { a in
            { f(a, $0) }
        }
    }

    /// Function that takes key and optional dictionary and returns optional value
    public func extract<Key, Value>(_ key: Key, _ json: Dictionary<Key, Any>?) -> Value? {
        return json.flatMap {
            cast($0[key])
        }
    }

    /// Function that takes key and return function that takes optional dictionary and returns optional value
    public func extract<Key, Value>(_ key: Key) -> (Dictionary<Key, Any>?) -> Value? {
        return curry(extract)(key)
    }

    /// Precedence group for our operator
    precedencegroup RightApplyPrecedence {
        associativity: right
        higherThan: AssignmentPrecedence
        lowerThan: TernaryPrecedence
    }

    /// Apply. g § f § a === g(f(a))
    infix operator § : RightApplyPrecedence
    public func §<A, B>(_ f: (A) -> B, _ a: A) -> B {
        return f(a)
    }

    /// Wrapper around operator "as".
    public func cast<A, B>(_ a: A) -> B? {
        return a as? B
    }

  1. Ed ecco la nostra magia: estrai il valore:

    let temperature = (extract("temperature") § extract("current") § json) ?? NSNotFound

Solo una riga di codice e nessuna forzatura apre o colata di tipo manuale. Questo codice funziona in playground, quindi puoi copiarlo e controllarlo. Ecco un'implementazione su GitHub.


0

Questo è un altro modo per risolvere il tuo problema. Quindi per favore controlla la soluzione sotto. Spero che ti possa aiutare.

let str = "{\"names\": [\"Bob\", \"Tim\", \"Tina\"]}"
let data = str.data(using: String.Encoding.utf8, allowLossyConversion: false)!
do {
    let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]
    if let names = json["names"] as? [String] {
        print(names)
    }
} catch let error as NSError {
    print("Failed to load: \(error.localizedDescription)")
}

0

Il problema è con il metodo di interazione API. L'analisi JSON viene modificata solo nella sintassi. Il problema principale è il modo di recuperare i dati. Quello che stai usando è un modo sincrono per ottenere i dati. Questo non funziona in ogni caso. Quello che dovresti usare è un modo asincrono per recuperare i dati. In questo modo, devi richiedere i dati tramite l'API e attendere che risponda con i dati. Puoi farlo con la sessione URL e le librerie di terze parti come Alamofire. Di seguito è riportato il codice per il metodo di sessione URL.

let urlString = "https://api.forecast.io/forecast/apiKey/37.5673776,122.048951"
let url = URL.init(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
    guard error == nil else {
        print(error)
    }
    do {
        let Data = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
        // Note if your data is coming in Array you should be using [Any]()
        //Now your data is parsed in Data variable and you can use it normally
        let currentConditions = Data["currently"] as! [String:Any]
        print(currentConditions)
        let currentTemperatureF = currentConditions["temperature"] as! Double
        print(currentTemperatureF)
    } catch let error as NSError {
        print(error)
    }
}.resume()

0
{
    "User":[
      {
        "FirstUser":{
        "name":"John"
        },
       "Information":"XY",
        "SecondUser":{
        "name":"Tom"
      }
     }
   ]
}

Se creo un modello utilizzando json precedente utilizzando questo collegamento [blog]: http://www.jsoncafe.com per generare la struttura codificabile o qualsiasi formato

Modello

import Foundation
struct RootClass : Codable {
    let user : [Users]?
    enum CodingKeys: String, CodingKey {
        case user = "User"
    }

    init(from decoder: Decoder) throws {
        let values = try? decoder.container(keyedBy: CodingKeys.self)
        user = try? values?.decodeIfPresent([Users].self, forKey: .user)
    }
}

struct Users : Codable {
    let firstUser : FirstUser?
    let information : String?
    let secondUser : SecondUser?
    enum CodingKeys: String, CodingKey {
        case firstUser = "FirstUser"
        case information = "Information"
        case secondUser = "SecondUser"
    }
    init(from decoder: Decoder) throws {
        let values = try? decoder.container(keyedBy: CodingKeys.self)
        firstUser = try? FirstUser(from: decoder)
        information = try? values?.decodeIfPresent(String.self, forKey: .information)
        secondUser = try? SecondUser(from: decoder)
    }
}
struct SecondUser : Codable {
    let name : String?
    enum CodingKeys: String, CodingKey {
        case name = "name"
    }
    init(from decoder: Decoder) throws {
        let values = try? decoder.container(keyedBy: CodingKeys.self)
        name = try? values?.decodeIfPresent(String.self, forKey: .name)
    }
}
struct FirstUser : Codable {
    let name : String?
    enum CodingKeys: String, CodingKey {
        case name = "name"
    }
    init(from decoder: Decoder) throws {
        let values = try? decoder.container(keyedBy: CodingKeys.self)
        name = try? values?.decodeIfPresent(String.self, forKey: .name)
    }
}

Parse

    do {
        let res = try JSONDecoder().decode(RootClass.self, from: data)
        print(res?.user?.first?.firstUser?.name ?? "Yours optional value")
    } catch {
        print(error)
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.