0
votes

I'm new to Swift 5.3 and having trouble retrieving my nested JSON data. My JSON data result looks like this:

 {
    "sites":[
       {
          "site_no":"16103000",
          "station_nm":"Hanalei River nr Hanalei, Kauai, HI",
          "dec_lat_va":22.1796,
          "dec_long_va":-159.466,
          "huc_cd":"20070000",
          "tz_cd":"HST",
          "flow":92.8,
          "flow_unit":"cfs",
          "flow_dt":"2020-08-18 07:10:00",
          "stage":1.47,
          "stage_unit":"ft",
          "stage_dt":"2020-08-18 07:10:00",
          "class":0,
          "percentile":31.9,
          "percent_median":"86.73",
          "percent_mean":"50.77",
          "url":"https:\/\/waterdata.usgs.gov\/hi\/nwis\/uv?site_no=16103000"
       }
    ]
 }

My structs look like this:

struct APIResponse: Codable {
    let sites: APIResponseSites
}

struct APIResponseSites: Codable {
    let station_nm: String
    let stage: Float
}

And my Decode SWIFT looks like this:

    let task = URLSession.shared.dataTask(with: url, completionHandler: {
        data, _, error in
        guard let data = data, error == nil else {
            return
        }
        
        var result: APIResponse?
        do {
            result = try JSONDecoder().decode(APIResponse.self, from: data)
        }
        catch {
            print("Failed to decode with error: \(error)")
        }
        
        guard let final = result else {
            return
        }
        
        print(final.sites.station_nm)
        print(final.sites.stage)
        

    })

And of course, I get an error that states:

Failed to decode with error: typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "sites", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

I know it has to do with 'sites' returning an array (a single one) but I don't know how to fix it. Any help would be greatly appreciated.

2
Hint: Why is "APIResponseSites" plural when it describes a single entry in the "sites" array? - gnasher729
I can't control the API. It is written to respond with an array, yes. - B-Money

2 Answers

1
votes

The error message it is pretty clear you need to parse an array of objects instead of a single object.

Just change your root declaration property from

let sites: APIResponseSites

to

let sites: [APIResponseSites]
0
votes
**1.** First "sites" is an array so replace 

let sites: APIResponseSites

with

let sites: [APIResponseSites]()


**2.** As sites is a array collection, please print value like given below:

print(final.sites.first?.station_nm ?? "")
print(final.sites.first?.stage ?? 0.0)


Final code is here:


struct APIResponse: Codable {
        let sites: [APIResponseSites]()
    }
    
    struct APIResponseSites: Codable {
        let station_nm: String
        let stage: Float
    }
    
    
    let task = URLSession.shared.dataTask(with: url, completionHandler: {
            data, _, error in
            guard let data = data, error == nil else {
                return
            }
        
            var result: APIResponse?
            do {
                result = try JSONDecoder().decode(APIResponse.self, from: data)
            }
            catch {
                print("Failed to decode with error: \(error)")
            }
            
            guard let final = result else {
                return
            }
            
            print(final.sites.first?.station_nm ?? "")
            print(final.sites.first?.stage ?? 0.0)
            
    
        })