JSON response decoding to nil in swift

1.4k Views Asked by At
struct Jresponse: Decodable{
            //var results: [Any]
            var resolution: Int?
            var elevation:  Int?
            var location: Int?
            var lat: Int?
            var lng: Int?
        }
        guard let url = URL(string: "https://maps.googleapis.com/maps/api/elevation/json?&locations=\(finalStringConvertedCoordinates)&key=\(apiKey)") else {
                    print("Error: cannot create URL")
                    return
                }
                // Create the url request
                var request = URLRequest(url: url)
                request.httpMethod = "GET"
                URLSession.shared.dataTask(with: request) { data, response, error in
                    guard error == nil else {
                        print("Error: error calling GET")
                        print(error!)
                        return
                    }
                    guard let data = data else {
                        print("Error: Did not receive data")
                        return
                    }
                    guard let response = response as? HTTPURLResponse, (200 ..< 299) ~= response.statusCode else {
                        print("Error: HTTP request failed")
                        return
                    }
                    do {
                        guard let jsonObject = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
                            print("Error: Cannot convert data to JSON object")
                            return
                        }
                        guard let prettyJsonData = try? JSONSerialization.data(withJSONObject: jsonObject, options: []) else {
                            print("Error: Cannot convert JSON object to Pretty JSON data")
                            return
                        }
                        guard let prettyPrintedJson = String(data: prettyJsonData, encoding: .utf8)
                        else {
                            print("Error: Could print JSON in String")
                            return
                        }
                        //print(prettyPrintedJson)
                        jsonResponse = prettyPrintedJson
                    } catch {
                        print("Error: Trying to convert JSON data to string")
                        return
                    }
                    let decoder = JSONDecoder()
                    let jrData = jsonResponse.data(using: .utf8)
                    let jsonResponseProcessed = try! decoder.decode(Jresponse.self, from: jrData! )
                    print(jsonResponseProcessed)
                }.resume()
        
            }

the code above contains both the request and decoding of the response, I am inexperienced with JSON which may be apparent.

The issue I have is the results being returned when printing are all nil.

previously I was not using decode and instead was trying to process the data into an array where individual values could be retrieved for comparison.

The array method was producing unmanageable data as the elements where not separated in a manageable order.

like this[The nil response][1]

OUTPUT with the inclusion of print("---> data: (String(data: data, encoding: .utf8))") looks like this.

[The output can be seen here][2]

---> data: Optional("{\n "results" : [\n {\n "elevation" : 11.59268283843994,\n "location" : {\n "lat" : 37.78533554077148,\n "lng" : -122.4059982299805\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.68190288543701,\n "location" : {\n "lat" : 37.78538513183594,\n "lng" : -122.4059143066406\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.86490249633789,\n "location" : {\n "lat" : 37.78548812866211,\n "lng" : -122.4059143066406\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.53255939483643,\n "location" : {\n "lat" : 37.78533554077148,\n "lng" : -122.4061584472656\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.46291351318359,\n "location" : {\n "lat" : 37.78533554077148,\n "lng" : -122.4063262939453\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.69645023345947,\n "location" : {\n "lat" : 37.78558731079102,\n "lng" : -122.4059143066406\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.79109859466553,\n "location" : {\n "lat" : 37.78569030761719,\n "lng" : -122.4059143066406\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.35733222961426,\n "location" : {\n "lat" : 37.78533554077148,\n "lng" : -122.4064865112305\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.57364559173584,\n "location" : {\n "lat" : 37.78533554077148,\n "lng" : -122.4066467285156\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.7429027557373,\n "location" : {\n "lat" : 37.78578948974609,\n "lng" : -122.4059143066406\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.02133083343506,\n "location" : {\n "lat" : 37.78589248657227,\n "lng" : -122.4059143066406\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.66207313537598,\n "location" : {\n "lat" : 37.78533554077148,\n "lng" : -122.4068145751953\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 11.85497093200684,\n "location" : {\n "lat" : 37.78536987304688,\n "lng" : -122.4069137573242\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.22011947631836,\n "location" : {\n "lat" : 37.78599548339844,\n "lng" : -122.4059143066406\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.59670543670654,\n "location" : {\n "lat" : 37.78609466552734,\n "lng" : -122.4059143066406\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.19275951385498,\n "location" : {\n "lat" : 37.78546905517578,\n "lng" : -122.4069137573242\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.13292598724365,\n "location" : {\n "lat" : 37.78557205200195,\n "lng" : -122.4069137573242\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.98763847351074,\n "location" : {\n "lat" : 37.78619766235352,\n "lng" : -122.4059143066406\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 13.3654317855835,\n "location" : {\n "lat" : 37.78629684448242,\n "lng" : -122.4059143066406\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.14237785339355,\n "location" : {\n "lat" : 37.78567504882812,\n "lng" : -122.4069137573242\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.26948738098145,\n "location" : {\n "lat" : 37.78577423095703,\n "lng" : -122.4069137573242\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 13.74397277832031,\n "location" : {\n "lat" : 37.78633499145508,\n "lng" : -122.4060211181641\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 14.1032075881958,\n "location" : {\n "lat" : 37.78633499145508,\n "lng" : -122.4061889648438\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.31325626373291,\n "location" : {\n "lat" : 37.7858772277832,\n "lng" : -122.4069137573242\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.36202812194824,\n "location" : {\n "lat" : 37.78598022460938,\n "lng" : -122.4069137573242\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 14.12999248504639,\n "location" : {\n "lat" : 37.78633499145508,\n "lng" : -122.4063491821289\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 14.4321174621582,\n "location" : {\n "lat" : 37.78633499145508,\n "lng" : -122.4065093994141\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 12.53042221069336,\n "location" : {\n "lat" : 37.78607940673828,\n "lng" : -122.4069137573242\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 13.14097881317139,\n "location" : {\n "lat" : 37.78618240356445,\n "lng" : -122.4069137573242\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 14.39413261413574,\n "location" : {\n "lat" : 37.78633499145508,\n "lng" : -122.4066696166992\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 14.40865802764893,\n "location" : {\n "lat" : 37.78633499145508,\n "lng" : -122.4068374633789\n },\n "resolution" : 0.5964969992637634\n },\n {\n "elevation" : 13.98401737213135,\n "location" : {\n "lat" : 37.78628158569336,\n "lng" : -122.4069137573242\n },\n "resolution" : 0.5964969992637634\n }\n ],\n "status" : "OK"\n}\n") Jresponse(resolution: nil, elevation: nil, location: nil, lat: nil, lng: nil) [1]: https://i.stack.imgur.com/uaRZZ.png [2]: https://i.stack.imgur.com/MWJZX.png

2

There are 2 best solutions below

6
On BEST ANSWER

Decoding failed

The most likely reason that you cannot get any data is that your data model (here defined as a struct Jresponse) does not fit the actual JSON format sent back by the backend.

I've quickly check google map api doc for elevation and it seems like you should receive a json object with an array of ElevationResult at the top level. Then each result would contain the resolution, the elevation and location.

Please refer to https://developers.google.com/maps/documentation/elevation/overview#ElevationResult

Correct Data Model


struct ElevationResponse: Decodable {
    let results: [ElevationResult]
}

struct ElevationResult: Decodable {
     let elevation: Double
     let location: LatLngLiteral
     let resolution: Double?
}

struct LatLngLiteral: Decodable {
     let lat: Double
     let lng: Double
}

Change model in your decoding

let jsonResponseProcessed = try! decoder.decode(ElevationResponse.self, from: data)

Side remarks

  1. The way you decode the data could be modernized and cleaner
  2. Pay attention to not use force unwrap and force try
  3. When posting your question, be careful to the code indentation, first select your code in Xcode and do a ctrl + i so that it improves its readability. Only then copy past it into your Stackoverflow question.
5
On

as suggested by @Joakim Danielson, you should modify your code to

 let jsonResponseProcessed = try! decoder.decode(Jresponse.self, from: data )

According to google docs, at: https://developers.google.com/maps/documentation/elevation/start

you should use this data structure: EDIT

struct Jresponse: Codable {
    let results: [Result]
    let status: String?
}

struct Result: Codable {
    let elevation: Double
    let location: Location
    let resolution: Double?
}

struct Location: Codable {
    let lat, lng: Double
}