Function is being executed more than once - ios

I have been knocking my head over this problem for a few days now. I have a function that
1) gets the snapshot values and then stores them into filteredLocations array
2) gets the location the user has pressed on the screen, then measures the distance between the two location points of where they pressed on the screen and the location from the snapshots
3) filters out the locations that meet the users radiusDistance and then places points on the map
The problem that I keep coming across though is with my print statements check 1 and check 2. They are being executed twice when it should only be once.
func addAnnotation(gestureRecognizer:UIGestureRecognizer){
filteredLocations.removeAll()
locations.removeAll()
let sampleRef = FIRDatabase.database().reference().child("SamplePost").child("post")
sampleRef.observeSingleEvent(of:.value, with: {(snapshot) in
if let result = snapshot.children.allObjects as? [FIRDataSnapshot] {
for child in result{
let dictionary = child.value as? [String: AnyObject]
let lat = dictionary?["lat"] as! Double
let long = dictionary?["long"] as! Double
let image = dictionary?["image"] as! String
let text = dictionary?["text"] as! String
let user = dictionary?["user"] as! String
let structure = MapPoints(Latitude: lat, Longitude: long, Image: image, Text: text, User: user)
self.filteredLocations.append(structure)
self.locations.append(structure)
print("check one \(self.filteredLocations.count)")
self.collectionView.reloadData()
}
}
let refined = Double(self.radiusDistanceNumber!)
print("check two \(self.filteredLocations.count)")
if gestureRecognizer.state == UIGestureRecognizerState.began{
self.removePointsAndClearArray()
let touchPoint = gestureRecognizer.location(in: self.mapView)
let newCoordinates = self.mapView.projection.coordinate(for: touchPoint)
let marker = GMSMarker(position: newCoordinates)
marker.title = "Selected location"
self.filteredLocations = self.locations.filter {
(locations) in
let userLocation = newCoordinates
let userLat = userLocation.latitude
let userLong = userLocation.longitude
let coordinateOne = CLLocation(latitude: userLat, longitude: userLong)
let coordinateTwo = CLLocation(latitude: CLLocationDegrees(locations.latitude!), longitude: CLLocationDegrees(locations.longitude!))
let distanceFromPoints = coordinateOne.distance(from: coordinateTwo)
let convertToMiles = distanceFromPoints*0.00062137
return convertToMiles < refined
}
print("check three \(self.filteredLocations.count)")
self.filteredLocations.map {
(location) in
let annotation = GMSMarker()
annotation.position = CLLocationCoordinate2D(latitude: CLLocationDegrees(location.latitude!), longitude: CLLocationDegrees(location.longitude!))
annotation.map = self.mapView
let camera = GMSCameraPosition.camera(withTarget: newCoordinates, zoom: 11)
self.mapView.animate(to: camera)
}
print("amount that is being counted \(self.filteredLocations.count)")
if self.filteredLocations.count <= 0 {
self.collectionView.isUserInteractionEnabled = false
} else{
self.collectionView.isUserInteractionEnabled = true
}
print("amount before reloading collectionView \(self.filteredLocations.count)")
self.collectionView.reloadData()
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseIn, animations: {
})
}
})
}

Related

Show Path on GoogleMaps in Swift4

My question is I want to draw the time between two points and my both location are coming from different controllers
for my first Location :-
extension HomeViewController: PickupLocationDelegate {
func didSelectLocation(place: GooglePlaceModel?) {
guard let place = place else {return}
enter_Location_TF.text = place.name
customDirectionViewTwo.isHidden = false
direction_Button.isHidden = true
location_Button.setImage(UIImage(named: "directionPoint")?.withRenderingMode(.alwaysOriginal), for: .normal)
pickupMarkers.forEach { (marker) in
marker.map = nil
}
let position = CLLocationCoordinate2D(latitude: place.latitude , longitude: place.longitude)
print(position)
let path = GMSMutablePath()
path.add(CLLocationCoordinate2D(latitude: place.latitude, longitude: place.longitude))
let marker = GMSMarker()
marker.position = position
marker.map = mapView
mapView.camera = GMSCameraPosition.camera(withTarget: position, zoom: 14)
pickupMarkers.append(marker)
}
}// My second location:-
extension HomeViewController: DropLocationDelegate {
func didSelectDrop(location: GooglePlaceModel?) {
guard let location = location else {return}
dropLocationLbl?.text = location.name
let position = CLLocationCoordinate2D(latitude: location.latitude , longitude: location.longitude)
print(position)
let marker = GMSMarker(position: position)
marker.icon = #imageLiteral(resourceName: "icon-drop-location")
marker.map = mapView
mapView.camera = GMSCameraPosition.camera(withTarget: position, zoom: 14)
pickupMarkers.append(marker)
let path = GMSMutablePath()
path.add(CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude))
pickupMarkers.forEach { (marker) in
path.add(marker.position)
}
let bounds = GMSCoordinateBounds(path: path)
mapView?.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 50.0))
}
}
marker are showing correctly but the path is not showing. I used the
GMSMutable path to draw the line between location but this is not working properly. Any help?
Preconditions
You need to get a Google directions api Key following this link
How to get a Google Directions API key and you also need to add this line
GMSPlacesClient.provideAPIKey("Your API KEY")
in your AppDelegate didFinishLaunchingWithOptions method
Now our issue
To find a path you need to use a method like this one, using googleapis.directions request, passing two CLLocationCoordinate2D then in the closure you will get an array of CLLocationCoordinate2D which are the waypoints of your path
public func getWaypointsAsArrayOfCoordinates(startLocation: CLLocationCoordinate2D, endLocation: CLLocationCoordinate2D, mode:String? = "walking", lang:String? = "en", finishedClosure:#escaping (([CLLocationCoordinate2D])->Void)){
var resultedArray:[CLLocationCoordinate2D] = []
let urlWithParams = "https://maps.googleapis.com/maps/api/directions/json" + self.customEncodedParameters(parametersDict: ["origin":"\(startLocation.latitude),\(startLocation.longitude)", "destination": "\(endLocation.latitude),\(endLocation.longitude)", "mode": mode!, "key":googleDirectionsApiKey, "language" : lang!])
var urlRequest = URLRequest(url: URL(string: urlWithParams)!)
urlRequest.httpMethod = "GET"
URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if let _ = error {
} else {
do {
if let jsonData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary {
let status = jsonData["status"] as! String
if(status == "OK") {
for routeDict in jsonData["routes"] as! Array<Dictionary<String, AnyObject>>
{
let legs = routeDict["legs"] as! Array<Dictionary<String, AnyObject>>
for leg in legs
{
let steps = leg["steps"] as! Array<Dictionary<String, AnyObject>>
for (index,step) in steps.enumerated(){
let start = step["start_location"] as! Dictionary<String,Any>
let end = step["end_location"] as! Dictionary<String,Any>
resultedArray.append(CLLocationCoordinate2D(latitude: start["lat"] as! CLLocationDegrees, longitude: start["lng"] as! CLLocationDegrees))
if(index == steps.count - 1) {
resultedArray.append(CLLocationCoordinate2D(latitude: end["lat"] as! CLLocationDegrees, longitude: end["lng"] as! CLLocationDegrees))
}
}
}
}
finishedClosure(resultedArray)
}
else {
print("not found")
finishedClosure([])
}
}
} catch {
print(error)
finishedClosure([])
}
}
}.resume()
}
Edit (Added missing function)
private func customEncodedParameters(parametersDict:[String:String]) ->String
{
let charactersAllowed = CharacterSet.urlQueryAllowed
var returnStr = ""
for key in parametersDict.keys {
if(returnStr.count == 0)
{
returnStr += "?"
returnStr += key.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
returnStr += "="
returnStr += parametersDict[key]!.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
}else{
returnStr += "&"
returnStr += key.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
returnStr += "="
returnStr += parametersDict[key]!.addingPercentEncoding(withAllowedCharacters: charactersAllowed)!
}
}
return returnStr
}
Then you can use it in your code like this
extension HomeViewController: DropLocationDelegate {
func didSelectDrop(location: GooglePlaceModel?) {
guard let location = location else {return}
dropLocationLbl?.text = location.name
let position = CLLocationCoordinate2D(latitude: location.latitude , longitude: location.longitude)
print(position)
let marker = GMSMarker(position: position)
marker.icon = #imageLiteral(resourceName: "icon-drop-location")
marker.map = mapView
mapView.camera = GMSCameraPosition.camera(withTarget: position, zoom: 14)
pickupMarkers.append(marker)
self.getWaypointsAsArrayOfCoordinates(startLocation: pickupMarkers.first.position , endLocation: pickupMarkers.last.position) { [weak self] (arrayOfCoordinates) in
DispatchQueue.main.async {
let path = GMSMutablePath()
for coordinate in arrayOfCoordinates {
path.add(coordinate)
}
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 2
polyline.strokeColor = UIColor.red
polyline.map = self?.mapView
let bounds = GMSCoordinateBounds(path: path)
self?.mapView?.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 50.0))
}
}
}
}

Swift Firebase call only display 1 post

Hi I am doing a firebase call which is a query to check for the same posts related to a NSDictionary value. The snapshot prints the posts that I want but only 1 post is being displayed. I am trying to think of why it is only displaying 1 post but having a tough time with this.
func getAllPosts(refreshing: Bool, refreshControl: UIRefreshControl?) {
MBProgressHUD.showAdded(to: self.view, animated: true)
Database.database().reference().child("posts").child(self.otherUser?["uid"] as! String).queryOrdered(byChild: "uid").queryEqual(toValue: self.otherUser?["uid"] as! String).observe(.childAdded, with: { snapshot in
if snapshot.exists() {
print(snapshot)
if let dictionary = snapshot.value as? [String: AnyObject] {
self.feeds = []
let uid = dictionary["uid"] as? String
let name = dictionary["businessName"] as? String
let address = dictionary["businessStreet"] as? String
let state = dictionary["businessCity"] as? String
let caption = dictionary["caption"] as? String
let downloadURL = dictionary["download_url"] as? String
let timestamp = dictionary["timestamp"] as? Double
let date = Date(timeIntervalSince1970: timestamp!/1000)
let postID = dictionary["postID"] as? String
let lat = Double(dictionary["businessLatitude"] as! String)
let long = Double(dictionary["businessLongitude"] as! String)
let businessLocation = CLLocation(latitude: lat!, longitude: long!)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters: Double = userLocation.distance(from: businessLocation)
let distanceInMiles: Double = distanceInMeters * 0.00062137
let distanceLabelText = String(format: "%.2f miles away", distanceInMiles)
let post = Post(uid: uid!, caption: caption!, downloadURL: downloadURL!, name: name!, date: date, address: address!, state: state!, distance: distanceLabelText, postID: postID!)
self.feeds.append(post)
// sort posts by date
self.feeds.sort {$0.date.compare($1.date) == .orderedDescending}
self.feedTableView.reloadData()
}
if refreshing {
refreshControl?.endRefreshing()
}
MBProgressHUD.hide(for: self.view, animated: true)
} else {
print("No Snapshot found")
MBProgressHUD.hide(for: self.view, animated: true)
}
})
}

How to get centre of the route map using GoogleMaps sdk

I want to display an image at the centre of the route map.
Below is the code used for directions between origin and destination:
let camera1 = GMSCameraPosition.camera(withLatitude: 45.4654, longitude:9.1859, zoom: 0.0)
self.mapView = GMSMapView.map(withFrame: cell.mapView.bounds, camera: camera1)
Alamofire.request(url, method: .post, parameters: nil, encoding: JSONEncoding.default, headers: nil)
.validate()
.responseJSON { response in
switch response.result {
case .success:
print(response.result.value!)
print("Validation Successful")
let dictResponse = response.result.value as! NSDictionary
print(dictResponse)
let aryRoutes = dictResponse .value(forKey:"routes" ) as! NSArray
print(aryRoutes)
var aryOverViewPolyLines :NSArray = []
aryOverViewPolyLines = aryRoutes .value(forKey: "overview_polyline") as! NSArray
print(aryOverViewPolyLines)
let strPoints = (aryOverViewPolyLines.value(forKey: "points") as! NSArray).object(at: 0)
let polygon = GMSPolygon()
polygon.path = GMSPath(fromEncodedPath: strPoints as! String)
print(strPoints)
let rectangle = GMSPolyline.init(path: polygon.path)
rectangle.strokeWidth = 2.0
rectangle.strokeColor = .white
rectangle.map = self.mapView
let mapBounds = GMSCoordinateBounds(path: polygon.path!)
self.mapView.animate(with: GMSCameraUpdate.fit(mapBounds, withPadding: 150.0))
case .failure(let error):
print(response.result.value!)
print(error)
}
}
Any suggestions how to solve this issue.
The solution from #mnabaa works by finding the middle path on the polyline. However, some paths could be a lot longer in distance than others. As a result, the point returned by Mnabaa's solution could end up somewhere a lot closer to the point A than the point B depending on the route. The extension below takes this problem into account:
extension GMSPolyline {
var middlePoint: CLLocationCoordinate2D? {
guard let path = path else {
return nil
}
var intermediatePoints: [CLLocationCoordinate2D] = []
for coordinateIndex in 0 ..< path.count() - 1 {
let startCoordinate = path.coordinate(at: coordinateIndex)
let endCoordinate = path.coordinate(at: coordinateIndex + 1)
let startLocation = CLLocation(latitude: startCoordinate.latitude, longitude: startCoordinate.longitude)
let endLocation = CLLocation(latitude: endCoordinate.latitude, longitude: endCoordinate.longitude)
let pathDistance = endLocation.distance(from: startLocation)
let intervalLatIncrement = (endLocation.coordinate.latitude - startLocation.coordinate.latitude) / pathDistance
let intervalLngIncrement = (endLocation.coordinate.longitude - startLocation.coordinate.longitude) / pathDistance
for intervalDistance in 0 ..< Int(pathDistance) {
let intervalLat = startLocation.coordinate.latitude + (intervalLatIncrement * Double(intervalDistance))
let intervalLng = startLocation.coordinate.longitude + (intervalLngIncrement * Double(intervalDistance))
let circleCoordinate = CLLocationCoordinate2D(latitude: intervalLat, longitude: intervalLng)
intermediatePoints.append(circleCoordinate)
}
}
return intermediatePoints[intermediatePoints.count / 2]
}
}
It's based on the article by Dylan Maryk.
func mapView(_ mapView: GMSMapView, didTap overlay: GMSOverlay) {
if let route = overlay as? GMSPolyline{
let coordinate = route.path!.coordinate(at: (route.path!.count()-1) / 2)
route.customMapInfoMarker!.position = CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude)
route.customMapInfoMarker.groundAnchor = CGPoint(x: 0.5, y: 0.5)
route.customMapInfoMarker.map = mapView
route.customMapInfoMarker.iconView = // YOUR CUSTOM IMAGEVIEW HERE
}
}
Extend GMSPolyline
extension GMSPolyline{
fileprivate struct AssociatedKey {
static var infoMarker = GMSMarker()
}
var customMapInfoMarker: GMSMarker! {
get {
if let marker = objc_getAssociatedObject(self, &AssociatedKey.infoMarker) as? GMSMarker {
return marker
}
return GMSMarker()
}
set (newValue){
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKey.infoMarker,
newValue,
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
}

Is it possible to not take over screen? Google Places IOS swift

Below codes from Google only return a place if I pick one from the list like the one I attached.
My question:
Is there any function available for me to store all the place's detail in a given coordinate? For example, if I have a coordinate of (51.5108396, -0.0922251), how can I get all the information of nearby places? I am not familiar with Json. Is there any example close to what I want? Thanks a lot.
This function placesClient.currentPlaceWithCallback is somehow close to what I want but it cannot use custom coordinate because it uses user's current coordinate.
//https://developers.google.com/places/ios-api/placepicker
let center = CLLocationCoordinate2DMake(51.5108396, -0.0922251)
let northEast = CLLocationCoordinate2DMake(center.latitude + 0.001, center.longitude + 0.001)
let southWest = CLLocationCoordinate2DMake(center.latitude - 0.001, center.longitude - 0.001)
let viewport = GMSCoordinateBounds(coordinate: northEast, coordinate: southWest)
let config = GMSPlacePickerConfig(viewport: viewport)
let placePicker = GMSPlacePicker(config: config)
placePicker?.pickPlaceWithCallback({ (place: GMSPlace?, error: NSError?) -> Void in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
return
}
if let place = place {
print("Place name \(place.name)")
print("Place address \(place.formattedAddress)")
print("Place attributions \(place.attributions)")
} else {
print("No place selected")
}
})
Fetching nearby places using google maps
Something is changed due to upgraded iOS version.
complete changed code
func fetchPlacesNearCoordinate(coordinate: CLLocationCoordinate2D, radius: Double, types:[String]) {
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?key=\("your api key")&location=\(coordinate.latitude),\(coordinate.longitude)&radius=\(radius)&rankby=prominence&sensor=true"
let typesString = types.count > 0 ? types.joinWithSeparator("|") : "food"
urlString += "&types=\(typesString)"
urlString = urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
let session = NSURLSession.sharedSession()
let placesTask = session.dataTaskWithURL(NSURL(string: urlString)!) {data, response, error in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
if let jsonResult = (try? NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as? NSDictionary {
let returnedPlaces: NSArray? = jsonResult["results"] as? NSArray
if returnedPlaces != nil {
for index in 0..<returnedPlaces!.count {
if let returnedPlace = returnedPlaces?[index] as? NSDictionary {
var placeName = ""
var latitude = 0.0
var longitude = 0.0
if let name = returnedPlace["name"] as? NSString {
placeName = name as String
}
if let geometry = returnedPlace["geometry"] as? NSDictionary {
if let location = geometry["location"] as? NSDictionary {
if let lat = location["lat"] as? Double {
latitude = lat
}
if let lng = location["lng"] as? Double {
longitude = lng
}
}
}
print("index", index, placeName, latitude, longitude)
}
}
}
}
}
placesTask.resume()
}

How to draw a proper polylines on google maps [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I have successfully drawn a polyline from point a to point b, but for some reason , it shows linear line not the correct waypoints
Here's the code
let path = GMSMutablePath()
path.addLatitude(3.1970044, longitude:101.7389365)
path.addLatitude(3.2058354, longitude:101.729536)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 5.0
polyline.geodesic = true
polyline.map = mapView
I was expecting that it would be doing some waypoints, but it just shows straight polylines
self.googleMapsView is the google maps view.
Example : self.getDirections("26.9211992,75.8185761", destination: "26.8472496,75.7691909", waypoints: ["26.8686811,75.7568383"], travelMode: nil, completionHandler: nil)
Example: google direction link
https://maps.googleapis.com/maps/api/directions/json?origin=26.9211992,75.8185761&destination=26.8472496,75.7691909&waypoints=optimize:true|26.8686811,75.7568383
let baseURLGeocode = "https://maps.googleapis.com/maps/api/geocode/json?"
let baseURLDirections = "https://maps.googleapis.com/maps/api/directions/json?"
var selectedRoute: Dictionary<NSObject, AnyObject>!
var overviewPolyline: Dictionary<NSObject, AnyObject>!
var originCoordinate: CLLocationCoordinate2D!
var destinationCoordinate: CLLocationCoordinate2D!
func getDirections(origin: String!, destination: String!, waypoints: Array<String>!, travelMode: AnyObject!, completionHandler: ((status: String, success: Bool) -> Void)?) {
if let originLocation = origin {
if let destinationLocation = destination {
var directionsURLString = baseURLDirections + "origin=" + originLocation + "&destination=" + destinationLocation
if let routeWaypoints = waypoints {
directionsURLString += "&waypoints=optimize:true"
for waypoint in routeWaypoints {
directionsURLString += "|" + waypoint
}
}
print(directionsURLString)
directionsURLString = directionsURLString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
let directionsURL = NSURL(string: directionsURLString)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let directionsData = NSData(contentsOfURL: directionsURL!)
do{
let dictionary: Dictionary<NSObject, AnyObject> = try NSJSONSerialization.JSONObjectWithData(directionsData!, options: NSJSONReadingOptions.MutableContainers) as! Dictionary<NSObject, AnyObject>
let status = dictionary["status"] as! String
if status == "OK" {
self.selectedRoute = (dictionary["routes"] as! Array<Dictionary<NSObject, AnyObject>>)[0]
self.overviewPolyline = self.selectedRoute["overview_polyline"] as! Dictionary<NSObject, AnyObject>
let legs = self.selectedRoute["legs"] as! Array<Dictionary<NSObject, AnyObject>>
let startLocationDictionary = legs[0]["start_location"] as! Dictionary<NSObject, AnyObject>
self.originCoordinate = CLLocationCoordinate2DMake(startLocationDictionary["lat"] as! Double, startLocationDictionary["lng"] as! Double)
let endLocationDictionary = legs[legs.count - 1]["end_location"] as! Dictionary<NSObject, AnyObject>
self.destinationCoordinate = CLLocationCoordinate2DMake(endLocationDictionary["lat"] as! Double, endLocationDictionary["lng"] as! Double)
let originAddress = legs[0]["start_address"] as! String
let destinationAddress = legs[legs.count - 1]["end_address"] as! String
let originMarker = GMSMarker(position: self.originCoordinate)
originMarker.map = self.googleMapsView
originMarker.icon = GMSMarker.markerImageWithColor(UIColor.greenColor())
originMarker.title = originAddress
let destinationMarker = GMSMarker(position: self.destinationCoordinate)
destinationMarker.map = self.googleMapsView
destinationMarker.icon = GMSMarker.markerImageWithColor(UIColor.redColor())
destinationMarker.title = destinationAddress
if waypoints != nil && waypoints.count > 0 {
for waypoint in waypoints {
let lat: Double = (waypoint.componentsSeparatedByString(",")[0] as NSString).doubleValue
let lng: Double = (waypoint.componentsSeparatedByString(",")[1] as NSString).doubleValue
let marker = GMSMarker(position: CLLocationCoordinate2DMake(lat, lng))
marker.map = self.googleMapsView
marker.icon = GMSMarker.markerImageWithColor(UIColor.purpleColor())
}
}
let route = self.overviewPolyline["points"] as! String
let path: GMSPath = GMSPath(fromEncodedPath: route)!
let routePolyline = GMSPolyline(path: path)
routePolyline.map = self.googleMapsView
}
else {
print("status")
//completionHandler(status: status, success: false)
}
}
catch {
print("catch")
// completionHandler(status: "", success: false)
}
})
}
else {
print("Destination is nil.")
//completionHandler(status: "Destination is nil.", success: false)
}
}
else {
print("Origin is nil")
//completionHandler(status: "Origin is nil", success: false)
}
}
For Swift 3.0
Please use this code...
func getDirections(origin: String!, destination: String!, waypoints: Array<String>!, travelMode: AnyObject!, completionHandler: ((_ status: String, _ success: Bool) -> Void)?) {
if let originLocation = origin {
if let destinationLocation = destination {
var directionsURLString = baseURLDirections + "origin=" + originLocation + "&destination=" + destinationLocation
if let routeWaypoints = waypoints {
directionsURLString += "&waypoints=optimize:true"
for waypoint in routeWaypoints {
directionsURLString += "|" + waypoint
}
}
print(directionsURLString)
directionsURLString = directionsURLString.addingPercentEscapes(using: String.Encoding.utf8)!
let directionsURL = NSURL(string: directionsURLString)
DispatchQueue.main.async( execute: { () -> Void in
let directionsData = NSData(contentsOf: directionsURL! as URL)
do{
let dictionary: Dictionary<String, AnyObject> = try JSONSerialization.jsonObject(with: directionsData! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String, AnyObject>
let status = dictionary["status"] as! String
if status == "OK" {
self.selectedRoute = (dictionary["routes"] as! Array<Dictionary<String, AnyObject>>)[0]
self.overviewPolyline = self.selectedRoute["overview_polyline"] as! Dictionary<String, AnyObject>
let legs = self.selectedRoute["legs"] as! Array<Dictionary<String, AnyObject>>
let startLocationDictionary = legs[0]["start_location"] as! Dictionary<String, AnyObject>
self.originCoordinate = CLLocationCoordinate2DMake(startLocationDictionary["lat"] as! Double, startLocationDictionary["lng"] as! Double)
let endLocationDictionary = legs[legs.count - 1]["end_location"] as! Dictionary<String, AnyObject>
self.destinationCoordinate = CLLocationCoordinate2DMake(endLocationDictionary["lat"] as! Double, endLocationDictionary["lng"] as! Double)
let originAddress = legs[0]["start_address"] as! String
let destinationAddress = legs[legs.count - 1]["end_address"] as! String
let originMarker = GMSMarker(position: self.originCoordinate)
originMarker.map = self.mapView
originMarker.icon = UIImage(named: "mapIcon")
originMarker.title = originAddress
let destinationMarker = GMSMarker(position: self.destinationCoordinate)
destinationMarker.map = self.mapView
destinationMarker.icon = UIImage(named: "mapIcon")
destinationMarker.title = destinationAddress
if waypoints != nil && waypoints.count > 0 {
for waypoint in waypoints {
let lat: Double = (waypoint.components(separatedBy: ",")[0] as NSString).doubleValue
let lng: Double = (waypoint.components(separatedBy: ",")[1] as NSString).doubleValue
let marker = GMSMarker(position: CLLocationCoordinate2DMake(lat, lng))
marker.map = self.mapView
marker.icon = UIImage(named: "mapIcon")
}
}
let route = self.overviewPolyline["points"] as! String
let path: GMSPath = GMSPath(fromEncodedPath: route)!
let routePolyline = GMSPolyline(path: path)
routePolyline.map = self.mapView
routePolyline.strokeColor = UIColor(red: 44, green: 134, blue: 200)
routePolyline.strokeWidth = 3.0
}
else {
print("status")
//completionHandler(status: status, success: false)
}
}
catch {
print("catch")
// completionHandler(status: "", success: false)
}
})
}
else {
print("Destination is nil.")
//completionHandler(status: "Destination is nil.", success: false)
}
}
else {
print("Origin is nil")
//completionHandler(status: "Origin is nil", success: false)
}
}
func drawMap ()
{
let str = String(format:"https://maps.googleapis.com/maps/api/directions/json?origin=\(originLatitude),\(originlongitude)&destination=\(destinationlatitude),\(destinationlongitude)&key=AIzaSyC8HZTqt2wsl14eI_cKxxxxxxxxxxxx")
Alamofire.request(str).responseJSON { (responseObject) -> Void in
let resJson = JSON(responseObject.result.value!)
print(resJson)
if(resJson["status"].rawString()! == "ZERO_RESULTS")
{
}
else if(resJson["status"].rawString()! == "NOT_FOUND")
{
}
else{
let routes : NSArray = resJson["routes"].rawValue as! NSArray
print(routes)
let position = CLLocationCoordinate2D(latitude: self.sellerlatitude, longitude: self.sellerlongitude)
let marker = GMSMarker(position: position)
marker.icon = UIImage(named: "mapCurrent")
marker.title = "Customer have selected same location as yours"
marker.map = self.Gmap
let position2 = CLLocationCoordinate2D(latitude: self.Buyyerlatitude, longitude: self.Buyyerlongitude)
let marker1 = GMSMarker(position: position2)
marker1.icon = UIImage(named: "makeupmarker")
marker1.title = self.locationAddress
marker1.map = self.Gmap
let pathv : NSArray = routes.value(forKey: "overview_polyline") as! NSArray
print(pathv)
let paths : NSArray = pathv.value(forKey: "points") as! NSArray
print(paths)
let newPath = GMSPath.init(fromEncodedPath: paths[0] as! String)
let polyLine = GMSPolyline(path: newPath)
polyLine.strokeWidth = 3
polyLine.strokeColor = UIColor.blue
polyLine.map = self.Gmap
let bounds = GMSCoordinateBounds(coordinate: position, coordinate: position2)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsetsMake(170, 30, 30, 30))
self.Gmap!.moveCamera(update)
}
}
}
For swift 5
func drawMap(SourceCordinate : CLLocationCoordinate2D, destinationcordinate :CLLocationCoordinate2D)
{
self.mapView.clear()
let str = String(format:"https://maps.googleapis.com/maps/api/directions/json?origin=\(SourceCordinate.latitude),\(SourceCordinate.longitude)&destination=\(destinationcordinate.latitude),\(destinationcordinate.longitude)&key=\(googleServiceKey)")
print(str)
Alamofire.request(str).responseJSON { (responseObject) -> Void in
let resJson = JSON(responseObject.result.value!)
print(resJson)
let routes : NSArray = resJson["routes"].rawValue as! NSArray
if(resJson["status"].rawString()! == "ZERO_RESULTS"){}
else if(resJson["status"].rawString()! == "NOT_FOUND"){}
else if routes.count == 0{}
else{
let routes : NSArray = resJson["routes"].rawValue as! NSArray
let position = CLLocationCoordinate2D(latitude: SourceCordinate.latitude, longitude: SourceCordinate.longitude)
/*let marker = GMSMarker(position: position)
marker.icon = #imageLiteral(resourceName: "ic_usermaplocation")//UIImage(named: "ic_MapPinGreyIcon")
marker.title = "" // Addres
marker.map = self.mapView
let position2 = CLLocationCoordinate2D(latitude: destinationcordinate.latitude, longitude: destinationcordinate.longitude)
let marker1 = GMSMarker(position: position2)
marker1.icon = #imageLiteral(resourceName: "ic_usermaplocation")//UIImage(named: "ic_LocationPinRedIcon")
marker1.title = "" // Destination Address
marker1.map = self.mapView*/
let pathv : NSArray = routes.value(forKey: "overview_polyline") as! NSArray
let paths : NSArray = pathv.value(forKey: "points") as! NSArray
let newPath = GMSPath.init(fromEncodedPath: paths[0] as! String)
let polyLine = GMSPolyline(path: newPath)
polyLine.strokeWidth = 5
polyLine.strokeColor = .black
let ThemeOrange = GMSStrokeStyle.solidColor( .black)
let OrangeToBlue = GMSStrokeStyle.gradient(from: .black, to: .black)
polyLine.spans = [GMSStyleSpan(style: ThemeOrange),
GMSStyleSpan(style: ThemeOrange),
GMSStyleSpan(style: OrangeToBlue)]
polyLine.map = self.mapView
let camera = GMSCameraPosition.camera(withLatitude: self.sourceLat, longitude: self.sourceLong, zoom: 15.0)
self.mapView.animate(to: camera)
/*let bounds = GMSCoordinateBounds(coordinate: position, coordinate: position2)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsets(top: 100, left: 100, bottom: 400, right: 100))
self.objMapVIew!.moveCamera(update)*/
}
}
}
A small improvement to Azharhussain Shaikh's answer.
func drawMap (src: CLLocationCoordinate2D, dst: CLLocationCoordinate2D) {
let str = String(format:"https://maps.googleapis.com/maps/api/directions/json?origin=\(src.latitude),\(src.longitude)&destination=\(dst.latitude),\(dst.longitude)&key=AIzaSyBKV************")
Alamofire.request(str).responseJSON { (responseObject) -> Void in
let resJson = JSON(responseObject.result.value!)
print(resJson)
if(resJson["status"].rawString()! == "ZERO_RESULTS")
{
}
else if(resJson["status"].rawString()! == "NOT_FOUND")
{
}
else{
let routes : NSArray = resJson["routes"].rawValue as! NSArray
print(routes)
let position = CLLocationCoordinate2D(latitude: src.latitude, longitude: src.longitude)
let marker = GMSMarker(position: position)
marker.icon = UIImage(named: "mapCurrent")
marker.title = "Customer have selected same location as yours"
marker.map = self.mapView
let position2 = CLLocationCoordinate2D(latitude: dst.latitude, longitude: dst.longitude)
let marker1 = GMSMarker(position: position2)
marker1.icon = UIImage(named: "makeupmarker")
marker1.title = "aa"
marker1.map = self.mapView
let pathv : NSArray = routes.value(forKey: "overview_polyline") as! NSArray
print(pathv)
let paths : NSArray = pathv.value(forKey: "points") as! NSArray
print(paths)
let newPath = GMSPath.init(fromEncodedPath: paths[0] as! String)
let polyLine = GMSPolyline(path: newPath)
polyLine.strokeWidth = 3
polyLine.strokeColor = UIColor.blue
polyLine.map = self.mapView
let bounds = GMSCoordinateBounds(coordinate: position, coordinate: position2)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsetsMake(170, 30, 30, 30))
self.mapView!.moveCamera(update)
}
}
}
To call the function :
let fromLoc = CLLocationCoordinate2DMake(latitude1, longitude1)
let toLoc = CLLocationCoordinate2DMake(latitude2, longitude2)
drawMap(src: fromLoc, dst: toLoc)
What I have changed:
1. Parameter passing
2. Position was given statically. I changed it.
You need to get all the points for the route. To get the route you need to use Google Direction API https://developers.google.com/maps/documentation/directions/. Then use the 1st result of array that will be the shortest one, use the encoded path to draw a poly line using pathFromEncodedPath: method.

Resources