Prawidłowe analizowanie JSON w Swift 3


123

Próbuję pobrać odpowiedź JSON i zapisać wyniki w zmiennej. Miałem wersje tego kodu działające w poprzednich wersjach Swift, aż do wydania wersji GM Xcode 8. Rzuciłem okiem na kilka podobnych postów na StackOverflow: Swift 2 Parsing JSON - Nie można indeksować wartości typu `` AnyObject '' i JSON Parsing w Swift 3 .

Jednak wydaje się, że przedstawione tam pomysły nie mają zastosowania w tym scenariuszu.

Jak poprawnie przeanalizować odpowiedź JSON w Swift 3? Czy coś się zmieniło w sposobie odczytywania JSON w Swift 3?

Poniżej znajduje się kod, o którym mowa (można go uruchomić na placu zabaw):

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)")
        }
    }
}

Edycja: oto przykład wyników wywołania API poprint(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]

Czy możesz umieścić przykładowe dane zwrócone przez wywołanie interfejsu API?
— Użytkownik

1
Tak, właśnie dodałem próbkę wyników wydrukowanych po wydrukowaniu (currentConditions). Mam nadzieję, że to pomoże.
— user2563039

Przeanalizuj json w swift4 przy użyciu protokołu Codable stackoverflow.com/a/52931265/9316566
— Naser Mohamed

Odpowiedzi:


172

Przede wszystkim nigdy nie ładuj danych synchronicznie ze zdalnego adresu URL , używaj zawsze metod asynchronicznych, takich jak URLSession.

„Any” nie ma elementów indeksu dolnego

występuje, ponieważ kompilator nie ma pojęcia, jakiego typu są obiekty pośrednie (na przykład currentlyw ["currently"]!["temperature"]), a ponieważ używasz typów kolekcji Foundation, tak jak NSDictionarykompilator nie ma żadnego pojęcia o typie.

Dodatkowo w Swift 3 wymagane jest poinformowanie kompilatora o typie wszystkich obiektów z indeksem.

Musisz rzutować wynik serializacji JSON na rzeczywisty typ.

Ten kod używa URLSessioni wyłącznie typów natywnych Swift

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()

Aby wydrukować wszystkie pary klucz / wartość, currentConditionsmożesz napisać

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

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

Uwaga dotycząca jsonObject(with data:

Wiele (wydaje się, że wszystkie) samouczków sugeruje .mutableContainerslub .mutableLeavesopcji, co w Swift jest całkowicie nonsensowne. Dwie opcje to starsze opcje Objective-C, służące do przypisywania wyniku do NSMutable...obiektów. W Swift każdy variable jest domyślnie zmienny i przekazanie którejkolwiek z tych opcji i przypisanie wyniku do letstałej nie ma żadnego efektu. Co więcej, większość implementacji i tak nigdy nie mutuje zdeserializowanego JSON.

Jedyny (rzadki) rozwiązaniem, które jest przydatne w SWIFT .allowFragmentsktóry jest wymagany w przypadku, gdy głównym celem JSON może być typu wartość ( String, Number, Booli null), niż jeden z typów Collection ( arraylub dictionary). Ale zwykle pomijaj optionsparametr, co oznacza brak opcji .

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

Kilka ogólnych uwag dotyczących analizowania formatu JSON

JSON to dobrze zorganizowany format tekstowy. Bardzo łatwo jest odczytać ciąg JSON. Przeczytaj uważnie tekst . Istnieje tylko sześć różnych typów - dwa typy kolekcji i cztery typy wartości.


Typy kolekcji to

  • Tablica - JSON: obiekty w nawiasach kwadratowych []- Swift: [Any]ale w większości przypadków[[String:Any]]
  • Słownik - JSON: obiekty w nawiasach klamrowych {}- Swift:[String:Any]

Typy wartości to

  • Ciąg znaków - JSON: dowolna wartość w podwójnych cudzysłowach "Foo", parzysta "123"lub "false"- Swift:String
  • Liczba - JSON: wartości liczbowe bez podwójnych cudzysłowów 123lub 123.0- Swift: IntlubDouble
  • Bool - JSON: truelub false nie w cudzysłowach - Swift: truelubfalse
  • null - JSON: null- Swift:NSNull

Zgodnie ze specyfikacją JSON wszystkie klucze w słownikach muszą być String.


Zasadniczo zawsze zaleca się używanie opcjonalnych powiązań do bezpiecznego rozpakowywania opcji

Jeśli obiekt główny jest Dictionary ( {}) rzutem na typ[String:Any]

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

i pobieraj wartości za pomocą kluczy z ( OneOfSupportedJSONTypesjest to kolekcja JSON lub typ wartości, jak opisano powyżej).

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

Jeśli obiekt główny jest tablicą ( []), rzut na typ[[String:Any]]

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

i iteruj po tablicy za pomocą

for item in parsedData {
    print(item)
}

Jeśli potrzebujesz elementu o określonym indeksie, sprawdź również, czy indeks istnieje

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

W rzadkich przypadkach, gdy JSON jest po prostu jednym z typów wartości - a nie typem kolekcji - musisz przekazać .allowFragmentsopcję i na przykład rzutować wynik na odpowiedni typ wartości

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

Firma Apple opublikowała obszerny artykuł na swoim blogu Swift: Praca z JSON w Swift


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

W Swift 4+ Codableprotokół zapewnia wygodniejszy sposób analizowania JSON bezpośrednio na struktury / klasy.

Na przykład podana próbka JSON w pytaniu (nieznacznie zmodyfikowana)

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}
"""

można zdekodować do struktury Weather. Typy jerzyków są takie same, jak opisano powyżej. Istnieje kilka dodatkowych opcji:

  • Ciągi reprezentujące an URLmożna dekodować bezpośrednio jako URL.
  • timeCałkowita może być dekodowany Datez dateDecodingStrategy .secondsSince1970.
  • Klucze JSON snaked_cased można przekonwertować na camelCase za pomocą rozszerzeniakeyDecodingStrategy .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)
}

Inne kodowane źródła:


To jest bardzo pomocne. Jestem po prostu ciekawy, dlaczego powyższy kod nie pokazuje widocznych danych wyjściowych, gdy jest uruchamiany na placu zabaw.
— user2563039

Jak wspomniano powyżej, musisz rzutować niejednoznaczny wynik funkcji dict!["currently"]!na słownik, z którego kompilator może bezpiecznie wywnioskować kolejną subskrypcję klucza.
— vadian,

1
Artykuł Apple jest całkiem fajny, ale z jakiegoś powodu nie mogłem go uruchomić ze Swift 3. Narzeka na Type [String: Any]? nie ma członków indeksu dolnego. Było z tym też kilka innych problemów, ale udało mi się to obejść. Czy ktoś ma przykład swojego kodu, który faktycznie działa?
— Shades

@Shades Zadaj pytanie i opublikuj swój kod. Najprawdopodobniej problem jest związany z nieopakowanymi opcjami.
— Vadian

Czy możesz umieścić przykładowe dane zwrócone przez wywołanie interfejsu API?
— Użytkownik

12

Dużą zmianą, jaka nastąpiła w Xcode 8 Beta 6 dla Swift 3, było to, że id teraz importuje jako Anyzamiast AnyObject.

Oznacza to, że parsedDatajest zwracany jako słownik najprawdopodobniej z typem [Any:Any]. Bez debugera nie mogłem dokładnie powiedzieć, co NSDictionaryzrobi twoje rzutowanie , ale błąd, który widzisz, jest taki, że dict!["currently"]!ma typAny

Jak więc to rozwiązać? Ze sposobu, w jaki się do niego odwołałeś, zakładam, że dict!["currently"]!jest to słownik, więc masz wiele opcji:

Najpierw możesz zrobić coś takiego:

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

W ten sposób otrzymasz obiekt słownikowy, do którego możesz następnie zapytać o wartości, dzięki czemu uzyskasz swoją temperaturę w następujący sposób:

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

Lub jeśli wolisz, możesz to zrobić w kolejce:

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

Mam nadzieję, że to pomoże, obawiam się, że nie miałem czasu napisać przykładowej aplikacji, aby ją przetestować.

Ostatnia uwaga: najłatwiejszą rzeczą do zrobienia może być po prostu przerzucenie ładunku JSON [String: AnyObject]na samym początku.

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

dict!["currently"]! as! [String: String]się rozbije
— vadian

Punktem, w którym się rozbił, była [„temperatura”] !! a także próbuję rzucić String na NSString - zweryfikowano, że nowe rozwiązanie działa swiftlang.ng.bluemix.net/#/repl/57d3bc683a422409bf36c391
— discorevilo

[String: String]nie może w ogóle działać, ponieważ istnieje kilka wartości liczbowych. To nie działa na placu zabaw dla komputerów Mac
— vadian,

@vadian ah, tak, nie zauważyłem ich, a szybka piaskownica pomogła je ukryć! - Poprawione [ponownie] teraz (i przetestowane na macOS). Dziękuję za zwrócenie uwagi :)
— 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

Właśnie w tym celu zbudowałem quicktype . Po prostu wklej przykładowy kod JSON, a quicktype wygeneruje następującą hierarchię typów dla danych 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
}

Generuje również kod organizacyjny bez zależności, aby przekonać wartość zwracaną JSONSerialization.jsonObjectdo a Forecast, w tym wygodny konstruktor, który przyjmuje ciąg JSON, dzięki czemu można szybko przeanalizować silnie wpisaną Forecastwartość i uzyskać dostęp do jej pól:

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

Możesz zainstalować quicktype z npm za pomocą interfejsu internetowegonpm i -g quicktype lub użyć interfejsu internetowego, aby uzyskać kompletny wygenerowany kod do wklejenia na swoim placu zabaw.


Linki nie działają.
— zwrócił ..

Fantastyczna oszczędność czasu! Dobra robota!
— marko

1
Genialne narzędzie. Dzięki.
— Ahmet Ardal

4

Zaktualizowany się isConnectToNetwork-Functionpotem, dzięki tym poście .

Napisałem na to dodatkową metodę:

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
}

Teraz możesz łatwo zadzwonić do tego w swojej aplikacji, gdziekolwiek chcesz

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, jaki byłby najlepszy sposób na dodanie tej funkcji do projektu? w jakimkolwiek contorllerze lub modelu?
— KamalPanhwar

hej, po prostu dodaj pierwszą metodę func loadingJSON (...) w dodatkowym pliku lub klasie szybkiego dostępu. Po tym możesz zadzwonić z każdego kontrolera w swoim projekcie
— Marco Weber

Próbowałem, ale uwielbiam pomysł demonstracji pełnego rozwiązania, a także tego, jak go używać, w tym metody pomocniczej isConnectedToNetwork (), to mi jest pomysł, jak zaimplementować to prawdopodobnie w dobrym kodzie
— Amr Angry

więc właśnie użyłem nowego pliku swift (lewy przycisk myszy na drzewie projektu, nowy plik ..., plik swift) i nazwałem go jsonhelper.swift. w tym pliku umieszczasz pierwszy kod, ładując JSON () i isConnectedToNetwork (). potem możesz użyć tych dwóch funkcji w każdej części swojego projektu. na przykład w loginVC, jako akcja przycisku logowania, możesz użyć drugiego kodu, oczywiście musisz zmienić domenę, ciąg znaków i wartości paseJson (parseJSON ["loginSuccessfull"]), aby pasowały do twój plik php
— Marco Weber

0

Swift ma potężne wnioskowanie o typie. Pozbądźmy się schematu „if let” lub „guard let” i wymuś rozpinanie używając podejścia funkcjonalnego:

  1. Oto nasz JSON. Możemy użyć opcjonalnego JSON lub zwykłego. W naszym przykładzie używam opcjonalnego:

    let json: Dictionary<String, Any>? = ["current": ["temperature": 10]]
  1. Funkcje pomocnicze. Musimy je napisać tylko raz, a następnie użyć ponownie w dowolnym słowniku:

    /// 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. A oto nasza magia - wyodrębnij wartość:

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

Tylko jedna linia kodu i bez wymuszania rozpakowywania lub ręcznego rzutowania typu. Ten kod działa na placu zabaw, więc możesz go skopiować i sprawdzić. Oto implementacja w GitHub.


0

To jest inny sposób rozwiązania problemu. Sprawdź więc poniższe rozwiązanie. Mam nadzieję, że to ci pomoże.

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

Problem dotyczy metody interakcji API. Analizowanie JSON zmienia się tylko w składni. Główny problem tkwi w sposobie pobierania danych. To, czego używasz, to synchroniczny sposób pobierania danych. To nie działa w każdym przypadku. Powinieneś używać asynchronicznego sposobu pobierania danych. W ten sposób musisz zażądać danych przez API i poczekać, aż dane odpowiedzą. Możesz to osiągnąć za pomocą sesji URL i bibliotek zewnętrznych, takich jak Alamofire. Poniżej znajduje się kod metody sesji 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"
      }
     }
   ]
}

Jeśli utworzę model przy użyciu poprzedniego json Używając tego linku [blog]: http://www.jsoncafe.com do generowania struktury kodowalnej lub dowolnego formatu

Model

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)
    }
}

Analizować

    do {
        let res = try JSONDecoder().decode(RootClass.self, from: data)
        print(res?.user?.first?.firstUser?.name ?? "Yours optional value")
    } catch {
        print(error)
    }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.