How to draw a Route between CurrentLocation to SearchedLocation in MkMapView in Swift

78 Views Asked by At

I need current location as a source and searched location as a destination, but I got the current location but here I am unable to bring coordinates(latitude and longitude) from searched location to destination. here my destination shows nil why? Below is the code please help me.

import UIKit
import MapKit
import CoreLocation
class MapSampViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate, UISearchBarDelegate {


    //Privacy - Location When In Use Usage Description, Privacy - Location Always Usage Description-------these two add in info.plist


    @IBOutlet weak var searchBar: UISearchBar!
    @IBOutlet weak var mapView: MKMapView!

    var source: CLLocationCoordinate2D!
    var destination: CLLocationCoordinate2D!

    var myaddress:String!
    var mycity:String!
    var mystate:String!
    var mycountry:String!
    var mytitle:String!
    var mylongitude:String!
    var mylatitude:String!
    var locationtoSearch:String!
    let locationManager = CLLocationManager()

    var currentlocationPlacemark: CLPlacemark!

    override func viewDidLoad() {

        super.viewDidLoad()
        searchBar.delegate = self
        mapView.delegate = self
        mapView.showsScale = true
        mapView.showsPointsOfInterest = true
        mapView.showsUserLocation = true

        if CLLocationManager.locationServicesEnabled()
        {
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.startUpdatingLocation()
        }
        // self.showDirection()
        }

    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {

        locationtoSearch = self.searchBar.text
        var geocoder:CLGeocoder = CLGeocoder()
        geocoder.geocodeAddressString(locationtoSearch!, completionHandler: {(placemarks, error) -> Void in
            if((error) != nil)
            {
            print("Error", error)
            }
            else if let placemark = placemarks?[0] as? CLPlacemark {

            var coordinates:CLLocationCoordinate2D = placemark.location!.coordinate
            var pointAnnotation:MKPointAnnotation = MKPointAnnotation()
                pointAnnotation.coordinate = coordinates
                print(coordinates)
              //  pointAnnotation.title = "\(String(describing: placemark.name)),\(String(describing: placemark.locality)), \(String(describing: placemark.administrativeArea)), \(String(describing: placemark.country))"

                self.myaddress = placemark.name

                self.mycity = placemark.locality

                self.mystate = placemark.administrativeArea

                self.mycountry = placemark.country

                pointAnnotation.title = "\(self.myaddress),\(self.mycity),\(self.mystate),\(self.mycountry)"

                self.mylongitude = String(stringInterpolationSegment: placemark.location?.coordinate.longitude)

                self.mylatitude = String(stringInterpolationSegment: placemark.location?.coordinate.latitude)

                self.mapView?.addAnnotation(pointAnnotation)

                self.mapView?.centerCoordinate = coordinates

                print("coordinates \(coordinates)")
                print("The latitude \(self.mylatitude)")
                print("The longitude \(self.mylongitude)")

              self.mapView?.selectAnnotation(pointAnnotation, animated: true)
            }
        })
        self.showDirection()//i called here or in view viewDidLoad
        let annotationsToRemove = mapView.annotations.filter { $0 !== self.mapView.userLocation

        }
        mapView.removeAnnotations( annotationsToRemove )
        }


       func showDirection()
       {
        source = locationManager.location?.coordinate//17.6881° N, 83.2131° E

       // let destination = CLLocationCoordinate2DMake(24.9511, 121.2358 )//If i give like this its working

        destination = CLLocationCoordinate2DMake(Double(mylongitude)!, Double(mylongitude)!)//fatal error: unexpectedly found nil while unwrapping an Optional value

        let sourcePlacemark = MKPlacemark(coordinate: source!)
        let destinationPlacemark = MKPlacemark(coordinate: destination)
        let sourceItem = MKMapItem(placemark: sourcePlacemark)
        let destinationItem = MKMapItem(placemark: destinationPlacemark)

        let directionReq = MKDirectionsRequest()
        directionReq.source = sourceItem
        directionReq.destination = destinationItem
        directionReq.transportType = .automobile

        let directions = MKDirections(request: directionReq)
        directions.calculate(completionHandler: {(response, error) in
            if error != nil {
                print("Error getting directions")
            }
            else {
                let route = response?.routes[0]
                self.mapView.add((route?.polyline)!, level:.aboveRoads)

                let rekt = route?.polyline.boundingMapRect
                self.mapView.setRegion(MKCoordinateRegionForMapRect(rekt!), animated: true)
                }
          })
      }

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {

        let rendrer = MKPolylineRenderer(overlay: overlay)
        rendrer.strokeColor = UIColor.blue
        rendrer.lineWidth = 3
        return rendrer
     }
}

here i called showDirection() func in searchBarSearchButtonClicked but it is getting called before coming here why?

1

There are 1 best solutions below

0
On

Direction requests are executed asynchronously. This means that the rest of your app doesn't wait for the direction to be fetched.

Your showDirection function is both fetching the direction and adding it to the mapView. It would be best to separate these functionalities. You can fetch the direction, update a route variable and have an observer on it which will add the route to the map once it has been fetched.

@IBOutlet weak var mapView: MKMapView!

var route: MKRoute? {
didSet {
    mapView.add((route?.polyline)!, level:.aboveRoads) }
}