How can I compare if I select my location in Swift? - ios

I have created an application that contains a mapView. I added a couple of annotations around my location. I want when I click on an annotation to show me the title in a label.
I did that and I took the title and put it in myLabel but when I'm clicking on my location, the application stops working and I get the error:
(Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value)
Here is my code:
import UIKit
import MapKit
import CoreLocation
import Foundation
class ViewControllermap: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mymap: MKMapView!
#IBOutlet weak var viewaddress: UILabel!
var selectedAnnotation: MKPointAnnotation?
var locationManager: CLLocationManager = CLLocationManager()
let regionInMeters:Double = 3000
var previouslocation: CLLocation?
var longitudeLocation:String = ""
var latituseLocation:String = ""
override func viewDidLoad() {
mymap.delegate = self
// checkLocationSevices()
super.viewDidLoad()
if let location = locationManager.location?.coordinate
{
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
mymap.setRegion(region, animated: true)
}
mymap.showsUserLocation = true
let location = CLLocationCoordinate2DMake(35.1623, 33.3178)
let annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "P1"
annotation.subtitle = "28 oct street"
mymap.addAnnotation(annotation)
let location2 = CLLocationCoordinate2DMake(35.1658, 33.3147)
let annotation2 = MKPointAnnotation()
annotation2.coordinate = location2
annotation2.title = "P2"
annotation2.subtitle = " Makedonitissis 46, Nicosia 2417"
mymap.addAnnotation(annotation2)
let location3 = CLLocationCoordinate2DMake(35.1600, 33.3770)
let annotation3 = MKPointAnnotation()
annotation3.coordinate = location3
annotation3.title = "P3"
annotation3.subtitle = " Kallipoleos 75, Nicosia 1678"
mymap.addAnnotation(annotation3)
let location4 = CLLocationCoordinate2DMake(35.1602, 33.3390)
let annotation4 = MKPointAnnotation()
annotation4.coordinate = location4
annotation4.title = "P4"
annotation4.subtitle = "Diogenis Str 6 Nicosia CY, 2404"
mymap.addAnnotation(annotation4)
let location5 = CLLocationCoordinate2DMake(35.1673, 33.3277)
let annotation5 = MKPointAnnotation()
annotation5.coordinate = location5
annotation5.title = "P5"
annotation5.subtitle = "Neas Egkomis 4, Egkomi"
mymap.addAnnotation(annotation5)
let location6 = CLLocationCoordinate2DMake(35.1680, 33.3375)
let annotation6 = MKPointAnnotation()
annotation6.coordinate = location6
annotation6.title = "P6"
annotation6.subtitle = "Neas Egkomis 4, Egkomi"
mymap.addAnnotation(annotation6)
let location7 = CLLocationCoordinate2DMake(35.1460, 33.3357)
let annotation7 = MKPointAnnotation()
annotation7.coordinate = location7
annotation7.title = "P7"
annotation7.subtitle = "Neas Egkomis 4, Egkomi"
mymap.addAnnotation(annotation7)
let location8 = CLLocationCoordinate2DMake(35.1580, 33.3275)
let annotation8 = MKPointAnnotation()
annotation8.coordinate = location8
annotation8.title = "P8"
annotation8.subtitle = "Neas Egkomis 4, Egkomi"
mymap.addAnnotation(annotation8)
// Do any additional setup after loading the view.
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if let annotationCoordinate = view.annotation?.coordinate {
self.selectedAnnotation = view.annotation as? MKPointAnnotation
viewaddress.text = "\(selectedAnnotation!.subtitle!)" as String
}
}
}
This error happens just when I click on my location and code is working for other annotations.
Anyone know how can I fix this?

Your selectedAnotation or its subtitle is nil .. thats why you are getting this crash ... use optional chaining or optional binding to avoid this ..
Roughly something like this ... // not tested code
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if let annotationCoordinate = view.annotation?.coordinate {
self.selectedAnnotation = view.annotation as? MKPointAnnotation
if let annnotation = selectedAnnotation , let subTitle = annnotation.subTitle as? String {
viewaddress.text = "\(subTitle)"
}
}
}

Related

Render multipolylines onto one map in swift

I have want to try and put a few different walking zones onto a map using polylines. The app works perfectly for one, however when i try and add walking zone 2 the polyine is not shown between zone points 2 at all. how can I get this to show the polyline for zone 1 and zone 2?
I can't seem to figure out where I am going wrong with this as it works perfectly for walking zone one but not when i add in the extra zone.
import UIKit
import MapKit
class customPin: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(pinTitle:String, pinSubTitle:String, location:CLLocationCoordinate2D) {
self.title = pinTitle
self.subtitle = pinSubTitle
self.coordinate = location
}
}
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//co-ordinates
let zone1S = CLLocationCoordinate2D(latitude: 52.100525, longitude: -9.623071)
let zone1E = CLLocationCoordinate2D(latitude: 52.07241, longitude: -9.575299)
let zone2S = CLLocationCoordinate2D(latitude: 52.054161, longitude: -9.385031)
let zone2E = CLLocationCoordinate2D(latitude: 52.081185, longitude: -9.247033)
//pins
let zone1PinS = customPin(pinTitle: "Zone 1 Start", pinSubTitle: "", location: zone1S)
let zone1PinE = customPin(pinTitle: "Zone 1 End", pinSubTitle: "", location: zone1E)
self.mapView.addAnnotation(zone1PinS)
self.mapView.addAnnotation(zone1PinE)
let zone2PinS = customPin(pinTitle: "Zone 2 Start", pinSubTitle: "", location: zone2S)
let zone2PinE = customPin(pinTitle: "Zone 2 End", pinSubTitle: "", location: zone2E)
self.mapView.addAnnotation(zone2PinS)
self.mapView.addAnnotation(zone2PinE)
let zone1PlacemarkS = MKPlacemark(coordinate: zone1S)
let zone1PlacemarkE = MKPlacemark(coordinate: zone1E)
let zone2PlacemarkS = MKPlacemark(coordinate: zone2S)
let zone2PlacemarkE = MKPlacemark(coordinate: zone2E)
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: zone1PlacemarkS)
directionRequest.destination = MKMapItem(placemark: zone1PlacemarkE)
//type of commute
directionRequest.transportType = .automobile
let directions = MKDirections(request: directionRequest)
directions.calculate { (response, error) in
guard let directionResonse = response else {
if let error = error {
print("we have error getting directions==\(error.localizedDescription)")
}
return
}
let route = directionResonse.routes[0]
self.mapView.addOverlay(route.polyline, level: .aboveRoads)
let rect = route.polyline.boundingMapRect
//zooming in on location
// self.mapView.setRegion(MKCoordinateRegion(rect), animated: true)
}
//set delegate for mapview
self.mapView.delegate = self
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = UIColor.red
renderer.lineWidth = 5.0
return renderer
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
when i try and add walking zone 2
But you don't add it. You are saying
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: zone1PlacemarkS)
directionRequest.destination = MKMapItem(placemark: zone1PlacemarkE)
You have only one direction request, and it uses the zone1PlacemarkS and zone1PlacemarkE, so those are the directions you get. You never make a direction request for the two zone2 placemarks; you just throw them away, unused. (Indeed, I would expect the compiler to warn you about that.)

MapKit: Route not being displayed between two annotations

Im trying to display a route between two annotations.
The annotations and the region work fine but the route won't show up and I have no idea why
It looks like the route is not being rendered at all.
I'm sure that the route exists because I tried to print it and it is in the directionResponse.routes
Any suggestions?
I'm using SwiftUI
Then this is included in a parent view.
import SwiftUI
import MapKit
import FirebaseFirestore
struct MapView: UIViewRepresentable {
var packageLocation: GeoPoint
var destination: GeoPoint
var driverLocation = CLLocationCoordinate2D()
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView {
MKMapView()
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolygonRenderer(overlay: overlay)
renderer.strokeColor = .blue
renderer.lineWidth = 2.0
return renderer
}
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
let requestLocation: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: packageLocation.latitude, longitude: packageLocation.longitude)
let destinationLocation: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: destination.latitude, longitude: destination.longitude)
//let span = MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1)
//let region = MKCoordinateRegion(center: requestLocation, span: span)
//uiView.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = requestLocation
annotation.title = "Package Title"
uiView.addAnnotation(annotation)
let annotation2 = MKPointAnnotation()
annotation2.coordinate = destinationLocation
annotation2.title = "Destiantion"
uiView.addAnnotation(annotation2)
let sourcePlacemark = MKPlacemark(coordinate: requestLocation)
let destinationPlacemark = MKPlacemark(coordinate: destinationLocation)
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: sourcePlacemark)
directionRequest.destination = MKMapItem(placemark: destinationPlacemark)
directionRequest.transportType = .automobile
let directions = MKDirections(request: directionRequest)
directions.calculate { (response, error) in
guard let directionResponse = response else {
if let error = error {
print(error.localizedDescription)
}
return
}
print(directionResponse)
let route = directionResponse.routes[0]
uiView.addOverlay(route.polyline, level: .aboveRoads)
let rect = route.polyline.boundingMapRect
uiView.setRegion(MKCoordinateRegion(rect), animated: true)
}
}
}
You've almost got it.
The one issue that you need to resolve is the use of the MKMapView delegate functions.
The easiest way to do that is to subclass MKMapView and make your own map view that has conforms to MKMapViewDelegate.
Firstly, create your own map view, subclassing MKMapView and conforming to MKMapViewDelegate. At the moment you're only really using the rendererFor overlay delegate method so I'll just implement that, but you can add other methods if you require them.
class WrappableMapView: MKMapView, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = .red
renderer.lineWidth = 4.0
return renderer
}
}
Then you need to update your UIViewRepresentable to use the new WrappableMapView that you just created. I have gone for making a functional example, so here I am passing in the request and destination locations. You can handle this how you want but at least this will give you something that works.
struct MyMapView: UIViewRepresentable {
#Binding var requestLocation: CLLocationCoordinate2D
#Binding var destinationLocation: CLLocationCoordinate2D
private let mapView = WrappableMapView()
func makeUIView(context: UIViewRepresentableContext<MyMapView>) -> WrappableMapView {
mapView.delegate = mapView // make sure we set our delegate to be the mapView we just created
return mapView
}
func updateUIView(_ uiView: WrappableMapView, context: UIViewRepresentableContext<MyMapView>) {
let requestAnnotation = MKPointAnnotation()
requestAnnotation.coordinate = requestLocation
requestAnnotation.title = "Package Title"
uiView.addAnnotation(requestAnnotation)
let destinationAnnotation = MKPointAnnotation()
destinationAnnotation.coordinate = destinationLocation
destinationAnnotation.title = "Destination"
uiView.addAnnotation(destinationAnnotation)
let requestPlacemark = MKPlacemark(coordinate: requestLocation)
let destinationPlacemark = MKPlacemark(coordinate: destinationLocation)
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: requestPlacemark)
directionRequest.destination = MKMapItem(placemark: destinationPlacemark)
directionRequest.transportType = .automobile
let directions = MKDirections(request: directionRequest)
directions.calculate { response, error in
guard let response = response else { return }
let route = response.routes[0]
uiView.addOverlay(route.polyline, level: .aboveRoads)
let rect = route.polyline.boundingMapRect
uiView.setRegion(MKCoordinateRegion(rect), animated: true)
// if you want insets use this instead of setRegion
// uiView.setVisibleMapRect(rect, edgePadding: .init(top: 50.0, left: 50.0, bottom: 50.0, right: 50.0), animated: true)
}
}
}
Finally we can put it all together with a ContentView that shows it works:
struct ContentView: View {
#State var requestLocation = CLLocationCoordinate2D(latitude: 51.509865, longitude: -0.118092)
#State var destinationLocation = CLLocationCoordinate2D(latitude: 51.501266, longitude: -0.093210)
var body: some View {
MyMapView(requestLocation: $requestLocation, destinationLocation: $destinationLocation)
}
}
This is what it should look like:
One thing to note, using the rendererFor overlay delegate function in the simulator causes an error. This only happens in the simulator and not on device, so don't be surprised if you see an error message like this in the console.
2019-11-08 18:50:30.034066+0000 StackOverflow[80354:9526181] Compiler error: Invalid library file

Add two coordinates in a button function to launch mapKit and start navigation between two points (Swift)

I'm using this class
import UIKit
import CoreLocation
import GoogleMaps
import GooglePlaces
import SwiftyJSON
import Alamofire
import MapKit
class FinalClass: UIViewController {
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var bottomInfoView: UIView!
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var distanceLabel: UILabel!
var userLocation:CLLocationCoordinate2D?
var places:[QPlace] = []
var index:Int = -1
var locationStart = CLLocation()
var locationEnd = CLLocation()
var mapView:GMSMapView!
var marker:GMSMarker?
override func loadView() {
super.loadView()
}
override func viewDidLoad() {
super.viewDidLoad()
guard index >= 0, places.count > 0 else {
return
}
let place = places[index]
let lat = place.location?.latitude ?? 1.310844
let lng = place.location?.longitude ?? 103.866048
// Google map view
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: lng, zoom: 12.5)
mapView = GMSMapView.map(withFrame: self.view.bounds, camera: camera)
mapView.autoresizingMask = [.flexibleHeight, .flexibleWidth, .flexibleTopMargin, .flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin]
self.containerView.addSubview(mapView)
// Add gesture
addSwipeGesture()
didSelect(place: place)
if userLocation != nil {
addMarkerAtCurrentLocation(userLocation!)
}
}
func addSwipeGesture() {
let directions: [UISwipeGestureRecognizerDirection] = [.right, .left]
for direction in directions {
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(sender:)))
gesture.direction = direction
self.bottomInfoView.addGestureRecognizer(gesture)
}
}
func addMarkerAtCurrentLocation(_ userLocation: CLLocationCoordinate2D) {
let marker = GMSMarker()
marker.position = userLocation
marker.title = "Your location"
marker.map = mapView
}
func didSelect(place:QPlace) {
guard let coordinates = place.location else {
return
}
// clear current marker
marker?.map = nil
// add marker
marker = GMSMarker()
marker?.position = coordinates
marker?.title = place.name
marker?.map = mapView
mapView.selectedMarker = marker
moveToMarker(marker!)
// update bottom info panel view
let desc = place.getDescription()
descriptionLabel.text = desc.characters.count > 0 ? desc : "-"
distanceLabel.text = "-"
// update distance
if userLocation != nil {
let dist = distance(from: userLocation!, to: coordinates)
distanceLabel.text = String.init(format: "Distance %.2f meters", dist)
self.drawPath(startLocation: userLocation!, endLocation: coordinates)
}
title = place.name
}
func moveToMarker(_ marker: GMSMarker) {
let camera = GMSCameraPosition.camera(withLatitude: marker.position.latitude,
longitude: marker.position.longitude,
zoom: 12.5)
self.mapView.animate(to: camera)
}
// distance between two coordinates
func distance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> CLLocationDistance {
let from = CLLocation(latitude: from.latitude, longitude: from.longitude)
let to = CLLocation(latitude: to.latitude, longitude: to.longitude)
return from.distance(from: to)
}
func handleSwipe(sender: UISwipeGestureRecognizer) {
guard index >= 0, places.count > 0 else {
return
}
if sender.direction == .left {
if index < places.count - 2 {
index += 1
didSelect(place: places[index])
}
} else if sender.direction == .right {
if index > 1 {
index -= 1
didSelect(place: places[index])
}
}
}
func drawPath(startLocation: CLLocationCoordinate2D, endLocation: CLLocationCoordinate2D) {
let from = CLLocation(latitude: startLocation.latitude, longitude: startLocation.longitude)
let to = CLLocation(latitude: endLocation.latitude, longitude: endLocation.longitude)
let origin = "\(from.coordinate.latitude),\(from.coordinate.longitude)"
let destination = "\(to.coordinate.latitude),\(to.coordinate.longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving"
Alamofire.request(url).responseJSON { response in
print(response.request as Any) // original URL request
print(response.response as Any) // HTTP URL response
print(response.data as Any) // server data
print(response.result as Any) // result of response serialization
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
// print route using Polyline
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor.black
polyline.map = self.mapView
}
}
}
#IBAction func navigationStart(_ sender: Any) {
}
with a google maps to add place markers, draw the direction on the map and show the distance between two points, now i would like to launch the navigator between startLocation: userLocation! and endLocation: coordinates but with some research i saw that i can not launch the navigator in the same view, i need to open the maps application, so i decided to add the MapKit and a button
#IBAction func navigationStart(_ sender: Any) {
}
so how can i do that by pressing the button the map application opens with direction from userLocation to coordinates ? I already looked to similar question but is a little different to my problem, because i already have the points but in different format.
Your question is a little confusing but if you want to open the maps app and show direction from a user's current location to another point on the map then you don't need to pass the user's location, just the destination:
Swift 4:
let coordinate = CLLocationCoordinate2DMake(51.5007, -0.1246)
let placeMark = MKPlacemark(coordinate: coordinate)
let mapItem = MKMapItem(placemark: placeMark)
mapItem.name = "Big Ben"
mapItem.openInMaps(launchOptions: [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving])
Objective C:
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(51.5007, -0.1246);
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate: coordinate];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:#"Big Ben"];
[mapItem openInMapsWithLaunchOptions:#{MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving}];

Draw route on map in swift 4

I want draw route between two coordinates in swift4.
and I am using this code,
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var myMap: MKMapView!
var myRoute : MKRoute!
override func viewDidLoad() {
super.viewDidLoad()
let point1 = MKPointAnnotation()
let point2 = MKPointAnnotation()
point1.coordinate = CLLocationCoordinate2DMake(25.0305, 121.5360)
point1.title = "Taipei"
point1.subtitle = "Taiwan"
myMap.addAnnotation(point1)
point2.coordinate = CLLocationCoordinate2DMake(24.9511, 121.2358)
point2.title = "Chungli"
point2.subtitle = "Taiwan"
myMap.addAnnotation(point2)
myMap.centerCoordinate = point2.coordinate
myMap.delegate = self
//Span of the map
myMap.setRegion(MKCoordinateRegionMake(point2.coordinate, MKCoordinateSpanMake(0.7,0.7)), animated: true)
let directionsRequest = MKDirectionsRequest()
let markTaipei = MKPlacemark(coordinate: CLLocationCoordinate2DMake(point1.coordinate.latitude, point1.coordinate.longitude), addressDictionary: nil)
let markChungli = MKPlacemark(coordinate: CLLocationCoordinate2DMake(point2.coordinate.latitude, point2.coordinate.longitude), addressDictionary: nil)
directionsRequest.source = MKMapItem(placemark: markChungli)
directionsRequest.destination = MKMapItem(placemark: markTaipei)
directionsRequest.transportType = MKDirectionsTransportType.automobile
let directions = MKDirections(request: directionsRequest)
directions.calculate(completionHandler: {
response, error in
if error == nil {
self.myRoute = response!.routes[0] as MKRoute
self.myMap.add(self.myRoute.polyline)
}
})
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) ->MKOverlayRenderer {
let myLineRenderer = MKPolylineRenderer(polyline: myRoute.polyline)
myLineRenderer.strokeColor = UIColor.red
myLineRenderer.lineWidth = 3
return myLineRenderer
}
}
and this code give me right answer
But when I change coordinates then it not show route.
new coordinates are
point1 = 26.9124, 75.7873
point2 = 26.9124, 76.7873
Looks like Apple Maps doesn't yet support India. (quora.com/…) I guess if this is a critical part of your app, you may have to consider Google Maps
Those new coordinates are in India, and it just looks like directions are not available there. I get an error that says "Error Domain=MKErrorDomain Code=4 "Directions Not Available" UserInfo={NSLocalizedDescription=Directions Not Available, MKErrorGEOError=-8, MKErrorGEOErrorUserInfo={ }, MKErrorGEOTransitIncidentKey=<_GEOTransitRoutingIncidentMessage: 0x60800023df20>, MKDirectionsErrorCode=0, NSLocalizedFailureReason=Directions are not available between these locations.}"
Thanx Rob for this answar.

How to display time on route as google maps

I have created route with multiple annotations.
I want to display text between annotations which exactly as attached screen shot.
Can any one help please?
Thanks
I tried something which will show the distance between two annotation but not when you tap on the MKPolylineOverlay. One more important thing I am not maintaining any standards.
Here is my controller structure.
import UIKit
import MapKit
class RouteViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
//Rest of the code see below
}
First of all I'll add some annotation to map in the viewDidLoad delegate method as below.
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
let annotation1 = MKPointAnnotation()
annotation1.title = "Times Square"
annotation1.coordinate = CLLocationCoordinate2D(latitude: 40.759011, longitude: -73.984472)
let annotation2 = MKPointAnnotation()
annotation2.title = "Empire State Building"
annotation2.coordinate = CLLocationCoordinate2D(latitude: 40.748441, longitude: -73.985564)
let annotation3 = MKPointAnnotation()
annotation3.title = "Some Point"
annotation3.coordinate = CLLocationCoordinate2D(latitude: 40.7484, longitude: -73.97)
let arrayOfPoints = [ annotation1, annotation2, annotation3]
self.mapView.addAnnotations(arrayOfPoints)
self.mapView.centerCoordinate = annotation2.coordinate
for (index, annotation) in arrayOfPoints.enumerate() {
if index < (arrayOfPoints.count-1) {
//I am taking the two consecutive annotation and performing the routing operation.
self.directionHandlerMethod(annotation.coordinate, ePoint: arrayOfPoints[index+1].coordinate)
}
}
}
In the directionHandlerMethod, I am performing the actual request for direction as below,
func directionHandlerMethod(sPoint: CLLocationCoordinate2D, ePoint: CLLocationCoordinate2D) {
let sourcePlacemark = MKPlacemark(coordinate: sPoint, addressDictionary: nil)
let destinationPlacemark = MKPlacemark(coordinate: ePoint, addressDictionary: nil)
let sourceMapItem = MKMapItem(placemark: sourcePlacemark)
let destinationMapItem = MKMapItem(placemark: destinationPlacemark)
let directionRequest = MKDirectionsRequest()
directionRequest.source = sourceMapItem
directionRequest.destination = destinationMapItem
directionRequest.transportType = .Automobile
let directions = MKDirections(request: directionRequest)
directions.calculateDirectionsWithCompletionHandler {
(response, error) -> Void in
guard let response = response else {
if let error = error {
print("Error: \(error)")
}
return
}
//I am assuming that it will contain one and only one result so I am taking that one passing to addRoute method
self.addRoute(response.routes[0])
}
}
Next I am adding the polyline route on map in the addRoute method as below,
func addRoute(route: MKRoute) {
let polyline = route.polyline
//Here I am taking the centre point on the polyline and placing an annotation by giving the title as 'Route' and the distance in the subtitle
let annoatation = MKPointAnnotation()
annoatation.coordinate = MKCoordinateForMapPoint(polyline.points()[polyline.pointCount/2])
annoatation.title = "Route"
let timeInMinute = route.expectedTravelTime / 60
let distanceString = String.localizedStringWithFormat("%.2f %#", timeInMinute, timeInMinute>1 ? "minutes" : "minute")
annoatation.subtitle = distanceString
self.mapView.addAnnotation(annoatation)
self.mapView.addOverlay(polyline)
}
Next I am implementing the rendererForOverlay delegate method as below,
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = UIColor.blueColor()
renderer.lineWidth = 2
renderer.lineCap = .Butt
renderer.lineJoin = .Round
return renderer
}
Next one is the important one delegate method which is viewForAnnotation. Here I am doing some things like placing the label instead of the annotation as below,
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.title != nil && annotation.title!! == "Route" {
let label = UILabel()
label.adjustsFontSizeToFitWidth = true
label.backgroundColor = UIColor.whiteColor()
label.minimumScaleFactor = 0.5
label.frame = CGRect(x: 0, y: 0, width: 100, height: 30)
label.text = annotation.subtitle ?? ""
let view = MKAnnotationView()
view.addSubview(label)
return view
}
return nil
}

Resources