简体   繁体   中英

Decoding JSON array on Swift

I have a simple array that I want to decode. I can deal with arrays in a JSON format with creating a new struct in the model class, and attributing that struct as an array in the main struct. But in this case, the json data is already on an array with 1 element. Therefore I should get the first element in the json response. I think I need to provide a decoder before I can access anything, but I don't know how that decoder model should be. The error I'm getting is:

typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))

JSON data I want to decode: (notice the data is on a array)

[
{
    "name": "United States",
    "topLevelDomain": [
        ".us"
    ],
    "alpha2Code": "US",
    "alpha3Code": "USA",
    "callingCodes": [
        "1"
    ],
    "capital": "Washington, D.C.",
    "altSpellings": [
        "US",
        "USA",
        "United States of America"
    ],
    "region": "Americas",
    "subregion": "Northern America",
    "population": 321645000,
    "latlng": [
        38,
        -97
    ],
    "demonym": "American",
    "area": 9629091,
    "gini": 48,
    "timezones": [
        "UTC-12:00",
        "UTC-11:00",
        "UTC-10:00",
        "UTC-09:00",
        "UTC-08:00",
        "UTC-07:00",
        "UTC-06:00",
        "UTC-05:00",
        "UTC-04:00",
        "UTC+10:00",
        "UTC+12:00"
    ],
    "borders": [
        "CAN",
        "MEX"
    ],
    "nativeName": "United States",
    "numericCode": "840",
    "currencies": [
        "USD",
        "USN",
        "USS"
    ],
    "languages": [
        "en"
    ],
    "translations": {
        "de": "Vereinigte Staaten von Amerika",
        "es": "Estados Unidos",
        "fr": "États-Unis",
        "ja": "アメリカ合衆国",
        "it": "Stati Uniti D'America"
    },
    "relevance": "3.5"
} ]

model class:

struct CountryModel: Codable {
    let country: [MyResponse]

}

struct MyResponse: Codable {
    let name: String
    let capital: String

}

Manager class:

struct CountryManager {


    let countryURL = "https://restcountries-v1.p.rapidapi.com/name/"

    func fetchData(_ countryName: String) {
        let urlString = "\(countryURL)\(countryName)"
        print(urlString)
        performRequest(urlString)

    }

    func performRequest(_ urlString: String){

        if let url = URL(string: urlString){

            var request = URLRequest(url:url)
            request.setValue("x-rapidapi-key", forHTTPHeaderField: "myapikey")

            let session = URLSession(configuration: .default)
            let task = session.dataTask(with: request) { (data, response, error) in
                if let e = error {
                    print(e)
                    return
                }
                if let safeData = data {
                    self.parseJSON(safeData)
                }
            }
            task.resume()
        }

    }


    func parseJSON(_ countryData: Data)  {
        let decoder = JSONDecoder()

        do {
            let decodedData = try decoder.decode([CountryModel].self, from: countryData)
            print(decodedData[0].country)

            }
        catch {
            print(error)
        }
    }


}

Most of the fields are missing from your model. Here is how it should look like instead:

struct Country: Codable {
    let name: String
    let topLevelDomains: [String]
    let alpha2Code: String
    let alpha3Code: String
    let callingCodes: [String]
    let capital: String
    let altSpellings: [String]
    let region: String
    let subregion: String
    let population: Int
    let latlng: [Int]
    let demonym: String
    let area: Int
    let gini: Int
    let timezones: [String]
    let borders: [String]
    let nativeName: String
    let numericCode: String
    let currencies: [String]
    let languages: [String]
    let translation: Translation
    let relevance: String
}

struct Translation: Codable {
    let de: String
    let es: String
    let fr: String
    let ja: String
    let it: String
}

I found out that there was a problem in my http request. I used Alamofire in the request part and I don't experience the problem anymore. The issue seemed to be related to the decoding but I don't know. I'm posting the final code if anyone experiences the same issue.

import Foundation
import Alamofire


struct CountryManager {


    let countryURL = "https://restcountries-v1.p.rapidapi.com/name/"

    func fetchData(_ countryName: String) {
        let urlString = "\(countryURL)\(countryName)"
        print(urlString)
        performRequest(urlString)

    }

    func performRequest(_ urlString: String){
        let headers: HTTPHeaders = [
            "x-rapidapi-host": "restcountries-v1.p.rapidapi.com",
            "x-rapidapi-key": "apices"
        ]

        AF.request(urlString, headers: headers).responseJSON { response in
            self.parseJSON(response.data!)
        }
    }



    func parseJSON(_ countryData: Data)  {
        let decoder = JSONDecoder()

        do {
            let decodedData = try decoder.decode(CountryAlias.self, from: countryData)
            print(decodedData[0].name)

            }
        catch {
            print(error)
        }
    }


}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM