0

I tried to get distance and duration from my position to selected marker on map using Google Directions API. I am using Alamofire + SwiftyJSON for doing the HTTP request and parsing the JSON that I get back.

I use this method for requesting and parsing JSON:

    func fetchDistanceFrom(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D, completionHandler: (String?, String?, NSError?) -> ()) -> ()
{
    let urlString = "https://maps.googleapis.com/maps/api/directions/json?key=\(apiKey)&origin=\(from.latitude),\(from.longitude)&destination=\(to.latitude),\(to.longitude)&mode=walking"

    var parsedDistance : String?
    var parsedDuration : String?

    request(.GET, urlString)
        .responseJSON { (req, res, json, error) in
            if(error != nil) {
                NSLog("Error: \(error)")
            }
            else {
                var json = JSON(json!)
                parsedDistance = json["routes"][0]["legs"][0]["distance"]["text"].stringValue as String!
                parsedDuration = json["routes"][0]["legs"][0]["duration"]["text"].stringValue as String!
                dispatch_async(dispatch_get_main_queue()) {
                    completionHandler(parsedDistance, parsedDuration, error)
                }
            }
    }
}

And I use it in my MapView class like this:

func mapView(mapView: GMSMapView!, didTapMarker marker: GMSMarker!) -> Bool {
    let selectedMarker = marker as! ExtendedMarker

    dataProvider.fetchDistanceFrom(mapView.myLocation.coordinate, to: marker.position){ (parsedDistance, parsedDuration, error) in

        let busStopDistance = parsedDistance
        let busStopDuration = parsedDuration

            selectedMarker.distance = "Distance: \(busStopDistance!)"
            selectedMarker.duration = "Duration: \(busStopDuration!)"
    }
    return false
}

to show the info afterwards in this method:

    func mapView(mapView: GMSMapView!, markerInfoContents marker: GMSMarker!) -> UIView! {
    let selectedMarker = marker as! ExtendedMarker

    if let infoView = UIView.viewFromNibName("MarkerInfoView") as? MarkerInfoView {

        infoView.nameLabel.text = selectedMarker.name
        infoView.linesTextView.text = selectedMarker.lines
        infoView.distanceLabel.text = selectedMarker.distance
        infoView.durationLabel.text = selectedMarker.duration

        return infoView
    } else {
        return nil
    }
}

But it doesn't work as it is supposed to, because somehow I can't get the distance and time on the first time I click the marker on map. It always shows up on second click on the marker. It looks like I get the JSON object from Google, it just isn't parsed before MapView shows the marker info.

Please, is there any way to fix this? I would be very thankful for any advice. Thank you.

andrejbroncek
  • 421
  • 5
  • 17
  • 1
    There is no need for `dispatch_async(dispatch_get_main_queue())` since the return block is already called in the main queue. – Stefan Salatic Apr 27 '15 at 17:04
  • 1
    I think that you would need to refresh map marker after you download the data since I believe that you can't just update them for some reason. I had a similar problem when I was downloading images async when tapped on marker. – Stefan Salatic Apr 27 '15 at 17:06
  • Thank you for pointing me in the right direction, I've got it working now :) – andrejbroncek Apr 27 '15 at 17:37
  • Use this http://stackoverflow.com/questions/28784034/swift-ios-google-map-path-to-coordinate/34435391#34435391 – LC 웃 Dec 23 '15 at 12:11

3 Answers3

0

I've got it working by forcing refresh on marker in didTapMarker method as shown below:

func mapView(mapView: GMSMapView!, didTapMarker marker: GMSMarker!) -> Bool {
    let selectedMarker = marker as! ExtendedMarker

    dataProvider.fetchDistanceFrom(mapView.myLocation.coordinate, to: marker.position){ (parsedDistance, parsedDuration, error) in

        let busStopDistance = parsedDistance
        let busStopDuration = parsedDuration

            selectedMarker.distance = "Distance: \(busStopDistance!)"
            selectedMarker.duration = "Duration: \(busStopDuration!)"

            mapView.selectedMarker = nil;
            mapView.selectedMarker = selectedMarker;
    }
    return false
}
Pang
  • 9,564
  • 146
  • 81
  • 122
andrejbroncek
  • 421
  • 5
  • 17
0

for get distance google maps sdk ios with swift 2.0 and Alamomfire:

//get Distance two points
func getDistanceFrom(de: CLLocationCoordinate2D, para: CLLocationCoordinate2D){

    let urlString = "https://maps.googleapis.com/maps/api/directions/json?key=\(GoogleMapsApiKey)&origin=\(de.latitude),\(de.longitude)&destination=\(para.latitude),\(para.longitude)&mode=walking"

    Alamofire.request(.POST, urlString, parameters: nil, encoding: .JSON, headers: nil)

        .responseJSON { (retorno) -> Void in
            //print(retorno.result.value)

            if retorno.result.isSuccess {
                if let km = retorno.result.value?.objectForKey("routes")?[0].objectForKey("legs")?[0].objectForKey("distance") as? NSDictionary{

                    if let km_KM = km.valueForKey("text") as? String {
                        dispatch_async(dispatch_get_main_queue(), { () -> Void in
                            self.LB_DistanciaKM.text = km_KM
                        })
                    }
                }
            }
    }
}
Pablo Ruan
  • 1,681
  • 1
  • 17
  • 12
0

With Swift 3 and Alamofire

func getGoogleMapGeoCodeDurationWithAlamofire(url: String) {
        Alamofire.request(url).responseJSON { response in
            let result = response.result
            if let result = result.value as? Dictionary<String, AnyObject> {
                if let routes = result["routes"] as? [Dictionary<String, AnyObject>] {
                    if let distance = routes[0]["legs"] as? [Dictionary<String, AnyObject>] {
                        print(distance[0]["distance"]?["text"] as! String)
                        print(distance[0]["duration"]?["text"] as! String)

                    }
                }
            }
        }

    }
user2620132
  • 155
  • 1
  • 1
  • 10