-3

Currently, I am using the Google Maps distance matrix API and get the following result when I run the following code:

func configureRoute(origin:String,destination:String){
    let jsonURL = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=place_id:\(origin)&destinations=place_id:\(destination)&key=MYAPIKEY"
    guard let url = URL(string: jsonURL ) else {return}

    URLSession.shared.dataTask(with: url) { (data, response, err) in

        guard let data = data else {return}

        let dataAsString = String(data: data, encoding: .utf8)
        print(dataAsString)
        }.resume()
    }

This is the result:

Optional("{\n   \"destination_addresses\" : [ \"Pittsburgh, PA, USA\" ],\n   \"origin_addresses\" : [ \"Philadelphia, PA, USA\" ],\n   \"rows\" : [\n      {\n         \"elements\" : [\n            {\n               \"distance\" : {\n                  \"text\" : \"305 mi\",\n                  \"value\" : 490750\n               },\n               \"duration\" : {\n                  \"text\" : \"4 hours 48 mins\",\n                  \"value\" : 17257\n               },\n               \"status\" : \"OK\"\n            }\n         ]\n      }\n   ],\n   \"status\" : \"OK\"\n}\n")

However from this result, I only want to get the duration of the distance which in this case is 4 hours and 48 mins. How would I only get the duration?

Upon trying a few suggestions, I placed my JSON url to get a formatted struct and got the following result:

struct Welcome: Codable {
let destinationAddresses, originAddresses: [String]
let rows: [Row]
let status: String

enum CodingKeys: String, CodingKey {
    case destinationAddresses = "destination_addresses"
    case originAddresses = "origin_addresses"
    case rows, status
}
}

struct Row: Codable {
let elements: [Element]
 }

struct Element: Codable {
let distance, duration: Distance
let status: String
}

struct Distance: Codable {
let text: String
let value: Int
 }

Using this, I implemented the following code:

func configureRoute(origin:String,destination:String){
    let jsonURL = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=place_id:\(origin)&destinations=place_id:\(destination)&key=MYAPIKEY"
    guard let url = URL(string: jsonURL ) else {return}
    print(jsonURL)

    URLSession.shared.dataTask(with: url) { (data, response, err) in

        guard let data = data else {return}

        do{
            let route = try JSONDecoder().decode(Element.self, from: data)
            print (route.duration)
        }
        catch let jsonErr{

        }
        let dataAsString = String(data: data, encoding: .utf8)
//            print(dataAsString)
        }.resume()
}

But my result for route.duration is still nothing.

Arnav GUPTA
  • 295
  • 1
  • 2
  • 17

2 Answers2

1
  1. Take your JSON response and paste it into the following online json to swift struct converter. JSON String to Swift struct converter

    {
    "name": "John",
    "age": 31,
    "city": "New York"
    }
    
  2. Now copy the generated struct.

    struct JSON: Codable {
     let name: String
     let age: Int
     let city: String
    }
    
  3. Decode your data response. Don't forget try catch and error handling

    let jsonRespone:JSON = try JSONDecoder().decode(JSON.self, data);
    
  4. Now you can access the data with your struct. If your JSON Response has some information that is not always there(error messages for example) just make your JSON Struct or that specific key optional.

    let cityName:String = jsonResponse.city
    let age:Int = jsonResponse.age
    let name:String = jsonResponse.name
    
mufumade
  • 400
  • 4
  • 16
  • I have added some details to the question, and followed your steps however the JSON response is a little strange. – Arnav GUPTA Aug 05 '18 at 13:16
  • If you paste your jsonURL in your browser you normally get the json string wich you can paste in the online converter. – mufumade Aug 05 '18 at 13:23
  • Ok, I did the following and still didn't work. I have updated my question with my results – Arnav GUPTA Aug 05 '18 at 14:12
  • If you paste your json string from your browser I will look into it – mufumade Aug 05 '18 at 14:14
  • Done, I cant place the exact string because it has my APIKey, but I have pasted the results above. – Arnav GUPTA Aug 05 '18 at 14:15
  • Ah now I see your problem! You have to imagine your struct as a tree. In your case the root is the struct `Welcome`. You can change it in the online tool or just in your code to a more suitable name. It is important to give the `JSONDecoder` the root of your json tree so again it is Welcome on your case. `do{ let rootJson = try JSONDecoder().decode(Welcome.self, from: data) print (rootJson.rows[0].elements[0].duration) }` rows and elements are arrays as you can see in the structs. – mufumade Aug 05 '18 at 14:35
-1

Using SwiftyJSON:

import SwiftyJSON

func configureRoute(origin:String,destination:String){
    let jsonURL = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=place_id:\(origin)&destinations=place_id:\(destination)&key=MYAPIKEY"
    guard let url = URL(string: jsonURL ) else {return}

    URLSession.shared.dataTask(with: url) { (data, response, err) in

        guard let data = data else {return}

        let dataAsString = String(data: data, encoding: .utf8)
        if let json = JSON(data: data){
            if let durationValue = json["rows"][0]["elements"][0]["duration"]["value"].int32 {
            //This is duration seconds, 17257
        }

        if let durationText = json["rows"][0]["elements"][0]["duration"]["text"].stringValue {
           //this is duration text, 4 hours 48 mins
        }
        print(dataAsString)
        }.resume()
    }
Moayad Al kouz
  • 1,342
  • 1
  • 9
  • 19
  • I am getting 2 errors "Call can throw, but it is not marked with 'try' and the error is not handled" and "Initializer for condition binding must be type Optional, not type JSON" and they are both with the line "if let json = JSON(data:data) – Arnav GUPTA Aug 05 '18 at 13:56