No accuracy when recording CLLocationPoints in Swift - ios

I'm working with a app to record walks, but I can't get the polylines to be as smooth as it looks in other apps, like runkeeper. I have tried with different activityType, desiredAccuracy and so on. I have tested on iPhone 5c, 6s and 7. It always looks like the example photo, it was recorded out in the open without any buildings near. Is there something I'm missing?
This is my viewDidLoad, viewWillAppear, viewDidAppear, locationManager and rendererFor overlay:
import UIKit
import MapKit
import CoreLocation
...
override func viewDidLoad() {
super.viewDidLoad()
myLocations = []
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.activityType = .fitness
manager.distanceFilter = 5
}
override func viewWillAppear(_ animated: Bool) {
//Map
logMap.delegate = self
logMap.mapType = MKMapType.standard
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()
manager.allowsBackgroundLocationUpdates = true
logMap.userTrackingMode = MKUserTrackingMode(rawValue: 1)!
}
override func viewDidAppear(_ animated: Bool) {
let status = CLLocationManager.authorizationStatus()
if status == .notDetermined || status == .denied || status ==
.authorizedWhenInUse {
manager.requestAlwaysAuthorization()
manager.requestWhenInUseAuthorization()
manager.requestLocation()
}else{
manager.startUpdatingLocation()
logMap.showsUserLocation = true
}
if status != .denied {
manager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager,
didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
manager.requestLocation()
}
if status == .authorizedAlways {
logMap.showsUserLocation = true
logMap.mapType = MKMapType(rawValue: 0)!
//logMap.userTrackingMode = MKUserTrackingMode(rawValue: 3)!
manager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations
locations: [CLLocation]){
if(isLoging==true){
if(myLocations.count > 1){
self.distance = self.distance +
Int(locations[0].distance(from: myLocations.last!))
}
myLocations.append(locations[0])
setDistance()
}
// paint line
if (myLocations.count > 1){
let sourceIndex = myLocations.count - 1
let destinationIndex = myLocations.count - 2
let c1 = myLocations[sourceIndex].coordinate
let c2 = myLocations[destinationIndex].coordinate
var a = [c1, c2]
let polyline = MKPolyline(coordinates: &a, count: a.count)
logMap.add(polyline)
}
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKPolyline {
let polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.strokeColor = UIColor.blue
polylineRenderer.lineWidth = 4
return polylineRenderer
}
return MKPolylineRenderer(overlay: overlay)
}
Result:

Try to set distanceFilter to k​CLDistance​Filter​None. This will notify you of every movement, but will consume the most battery.
Even if you are outside of a building you still don't get perfect accuracy.
If I were to guess other fitness app assume that you don't run through buildings and stuff, so they adjust you path to match streets.
I know for a fact that Strava shows my path through buildings and gardens, because they don't get perfect accuracy.

Do this to get best accuracy to get your location everytime.
override func loadView() {
print("loadView called")
// Enable some map settings
map.isMyLocationEnabled = true
map.settings.myLocationButton = true
map.settings.compassButton = true
map.settings.scrollGestures = true
map.settings.zoomGestures = true
map.delegate = self
view = map
}
override func viewDidLoad() {
super.viewDidLoad()
print("ViewDidLoad called")
// Configuring location manager.
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
locationManager.startMonitoringSignificantLocationChanges()
}
Add Delegate in ViewController: CLLocationManagerDelegate, GMSMapViewDelegate
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locationManager function called")
// Fetch current location coordinates
let locValue:CLLocationCoordinate2D = (locationManager.location?.coordinate)!
currentLatitude = locValue.latitude
currentLongitude = locValue.longitude
print("Current Location = \(currentLatitude!), \(currentLongitude!)")
// Zoom to current location
let target = CLLocationCoordinate2D(latitude: currentLatitude!, longitude: currentLongitude!)
map.camera = GMSCameraPosition.camera(withTarget: target, zoom: 17)
locationManager.stopUpdatingLocation()
//DispatchQueue.main.asyncAfter(deadline: .now() + 1.75, execute: {self.webResponse()})
}

Related

Adding search bar and location button to MapKit view controller

This may be an easy solution but I've tried everything it seems. I cannot seem to add a search box and button to my MapKit view controller after my login window. I added my MapKit programatically rather than from the story board and can't seem to add any overlays onto it. Here is the code where I've previously tried to add UIButton and UITextField but it doesn't seem to appear so I've removed it.
I'm trying to get the user to input an address to where they'll get walking directions from their current location with a route poly overlay and also a button for finding their current location, like in the bottom corner of the normal Maps app.
import MapKit
import CoreLocation
class mapViewController: UIViewController, CLLocationManagerDelegate {
let mapView = MKMapView()
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
setupMapView()
checkLocationServices()
}
func setupMapView() {
view.addSubview(mapView)
mapView.translatesAutoresizingMaskIntoConstraints = false
mapView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
mapView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
mapView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
mapView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
let region = MKCoordinateRegion.init(center: location.coordinate, latitudinalMeters: 4000, longitudinalMeters: 4000)
mapView.setRegion(region, animated: true)
}
func checkLocationAuthorization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
mapView.showsUserLocation = true
followUserLocation()
locationManager.startUpdatingLocation()
break
case .denied:
// Show alert
break
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .restricted:
// Show alert
break
case .authorizedAlways:
break
}
}
func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() {
setupLocationManager()
checkLocationAuthorization()
} else {
// the user didn't turn it on
}
}
func followUserLocation() {
if let location = locationManager.location?.coordinate {
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: 4000, longitudinalMeters: 4000)
mapView.setRegion(region, animated: true)
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkLocationAuthorization()
}
func setupLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
}
EDIT: I have managed to add a UISearchController:
let searchController: UISearchController = {
let sc = UISearchController()
sc.obscuresBackgroundDuringPresentation = false
sc.searchBar.placeholder = NSLocalizedString("Search Directions", comment: "")
sc.searchBar.barTintColor = .systemPink
return sc
}()

How to fix Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value?

I have a problem with the Users Location.
When im trying to build the program it gets this error code: (Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value)
My code:
import UIKit
import MapKit
class ViewController: UIViewController {
private let locationManager = CLLocationManager()
private var currentCoordinate: CLLocationCoordinate2D?
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
configerLocationServices()
}
private func configerLocationServices() {
locationManager.delegate = self
let status = CLLocationManager.authorizationStatus()
if status == .notDetermined {
locationManager.requestWhenInUseAuthorization()
} else if status == .authorizedAlways || status == .authorizedWhenInUse {
beginLocationUpdates(locationManager: locationManager)
}
}
private func beginLocationUpdates(locationManager: CLLocationManager) {
mapView.showsUserLocation = true //<--- the problem is here
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
private func zoomToLastestLocation(with coordinate: CLLocationCoordinate2D) {
let zoomRegion = MKCoordinateRegion(center: coordinate, latitudinalMeters: 10000, longitudinalMeters: 10000)
mapView.setRegion(zoomRegion, animated: true)
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("Did get latest Location")
guard let latestLocation = locations.first else { return }
if currentCoordinate == nil {
zoomToLastestLocation(with: latestLocation.coordinate)
}
currentCoordinate = latestLocation.coordinate
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
print("The Status changed")
if status == .authorizedAlways || status == .authorizedWhenInUse {
self.beginLocationUpdates(locationManager: manager)
}
}
}
I don't know what im doing wrong, has anyone the solution?
Thank you in advance.
private func setNewLoaction(lat:CLLocationDegrees,long:CLLocationDegrees,markerTitle:String){
let center = CLLocationCoordinate2D(latitude: lat, longitude: long)
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: long, zoom: 15)
self.googleMapsView?.camera = camera
self.googleMapsView?.isMyLocationEnabled = true
let marker = GMSMarker(position: center)
marker.map = self.googleMapsView
marker.title = markerTitle
locationManager.stopUpdatingLocation()
}
//MARK:- MAP VIEW
private func setUpMap(){
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
self.googleMapsView = GMSMapView (frame: CGRect(x: 0, y: 0, width: self.view.frame.width-30, height: self.mapView.frame.height))
self.googleMapsView?.settings.compassButton = true
self.googleMapsView?.isMyLocationEnabled = true
self.googleMapsView?.settings.myLocationButton = true
self.mapView.addSubview(self.googleMapsView!)
}
I have called setUpMap in ViewDidload and this setLoaction function in GMSAutocompleteViewControllerDelegate =:
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
destinationField.text = place.formattedAddress
destinationLatitude = place.coordinate.latitude
destinationLongitutude = place.coordinate.longitude
setNewLoaction(lat: destinationLatitude!, long: destinationLongitutude!, markerTitle: "Destination Location")
dismiss(animated: true, completion: nil)
}
you can call this anywhere as per you need, do remember to turn on location when asked for permission and if using in simlulator go to Features/Loaction/custom Location
I have now an other code for the same thing it is shorter than the old one.
Here is the code:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController {
#IBOutlet var mapView: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.startUpdatingLocation()
mapView.showsUserLocation = true // <--- Crash
}
}
And now it gets the same problem as the old one :(

MKPolyline isn't drawing on the map. How can I resolve this issue?

I am trying to draw an MKPolyline on a map. When I do a simulated run on the app, the location moves correctly but no line is drawn. How can I resolve this issue?
mapView.delegate = self
mapView.showsUserLocation = true
mapView.mapType = MKMapType(rawValue: 0)!
mapView.userTrackingMode = MKUserTrackingMode(rawValue: 2)!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
mapView.mapType = MKMapType(rawValue: 0)!
}
override func viewWillAppear(_ animated: Bool) {
locationManager.startUpdatingHeading()
locationManager.startUpdatingLocation()
}
override func viewWillDisappear(_ animated: Bool) {
locationManager.stopUpdatingHeading()
locationManager.stopUpdatingLocation()
}
// MARK: - CLLocationManager delegate
func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
//drawing path or route covered
if let oldLocationNew = oldLocation as CLLocation?{
let oldCoordinates = oldLocationNew.coordinate
let newCoordinates = newLocation.coordinate
var area = [oldCoordinates, newCoordinates]
var polyline = MKPolyline(coordinates: &area, count: area.count)
mapView.add(polyline)
}
//calculation for location selection for pointing annoation
if let previousLocationNew = previousLocation as CLLocation?{
//case if previous location exists
if previousLocation.distance(from: newLocation) > 200 {
addAnnotationsOnMap(locationToPoint: newLocation)
previousLocation = newLocation
}
}
else{
//case if previous location doesn't exists
addAnnotationsOnMap(locationToPoint: newLocation)
previousLocation = newLocation
}
}
// MARK: - MKMapView delegate
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
if (overlay is MKPolyline) {
var pr = MKPolylineRenderer(overlay: overlay)
pr.strokeColor = UIColor.red
pr.lineWidth = 5
return pr
}
return nil
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if startDate == nil {
startDate = Date()
} else {
print("elapsedTime:", String(format: "%.0fs", Date().timeIntervalSince(startDate)))
timeLabel.text="\(Date().timeIntervalSince(startDate))"
}
if startLocation == nil {
startLocation = locations.first
} else if let location = locations.last {
traveledDistance += lastLocation.distance(from: location)
print("Traveled Distance:", traveledDistance)
distanceLabel.text="\(traveledDistance)"
print("Straight Distance:", startLocation.distance(from: locations.last!))
}
lastLocation = locations.last
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
if (error as? CLError)?.code == .denied {
manager.stopUpdatingLocation()
manager.stopMonitoringSignificantLocationChanges()
}
}
MKPolyline should be drawn as the user moves.
The signature for mapView(_:rendererFor:) is incorrect. It has changed. It is now:
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
switch overlay {
case let polyline as MKPolyline:
let renderer = MKPolylineRenderer(polyline: polyline)
renderer.strokeColor = .red
renderer.lineWidth = 5
return renderer
// you can add more `case`s for other overlay types as needed
default:
fatalError("Unexpected MKOverlay type")
}
}
If you add a print statement or breakpoint inside your current method, I believe you will find that it’s not being called. And, of course, make sure that you’ve set the delegate of your map view, either in IB or programmatically.
By the way, the old locationManager(_:didUpdateTo:from:) is deprecated. Use locationManager(_:didUpdateLocations:) instead. You’ll have to maintain your own reference to the savedLocation and the savedPolyline:
var savedLocation: CLLocation?
var savedPolyline: MKPolyline?
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last(where: { $0.horizontalAccuracy >= 0 }) else { return }
var polyline: MKPolyline?
if let oldCoordinate = savedLocation?.coordinate {
let coordinates = [oldCoordinate, location.coordinate]
polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
mapView.addOverlay(polyline!)
}
// if you want to remove the old one
//
// if let savedPolyline = savedPolyline {
// mapView.removeOverlay(savedPolyline)
// }
//
// savedPolyline = polyline
savedLocation = location
// ...
}

Can't get User Location Using MKMapViewDelegate

I have been reading tutorials about getting user location for several hours, yet I cannot seem to get it. I have my ViewController class implementing CLLocationManagerDelegate and MKMapViewDelegate.
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.requestWhenInUseAuthorization()
self.mapView.delegate = self
self.mapView.showsUserLocation = true
print("Is User Location Visible: \(self.mapView.userLocation.location?.coordinate.latitude)")
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
print("Authorization Status = \(CLLocationManager.authorizationStatus() == .Denied || CLLocationManager.authorizationStatus() == CLAuthorizationStatus.NotDetermined)")
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
locationManager.delegate = self
}
else{
print("location services disabled")
}
}
This seems like it would work, as I have set showsUserLocation to true with MKMapView and started updating location services with CLLocationManager.
However, the printout of viewDidLoad() is:
Is User Location Visible: nil
Authorization Status = false
Whenever I try to access user location, it's nil.
I have NSLocationWhenInUseUsageDescription set in Info.plist as well, it successfully asked me if I want to allow location services and I clicked yes.
Thanks
EDIT:
Here is the full code of MapViewController.swift:
import UIKit
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
var mapView: MKMapView!
let locationManager = CLLocationManager()
override func loadView() {
// create a map view
mapView = MKMapView()
// set the map view we just created as the view for this controller
view = mapView
let ​​​​​​​​​​​​​​​​segmentedControl = UISegmentedControl(items: ["Standard", "Hybrid", "Satellite", "My Location"])
​​​​​​​​​​​​​​​​segmentedControl.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.5)
​​​​​​​​​​​​​​​​segmentedControl.selectedSegmentIndex = 0
​​​​​​​​​​​​​​​​segmentedControl.addTarget(self, action: #selector(MapViewController.mapTypeChanged(_:)), forControlEvents: .ValueChanged)
​​​​​​​​​​​​​​​​segmentedControl.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(​​​​​​​​​​​​​​​​segmentedControl)
let topConstraint = ​​​​​​​​​​​​​​​​segmentedControl.topAnchor.constraintEqualToAnchor(topLayoutGuide.bottomAnchor, constant: 8)
let margins = view.layoutMarginsGuide
let leadingConstraint = ​​​​​​​​​​​​​​​​segmentedControl.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor)
let trailingConstraint = ​​​​​​​​​​​​​​​​segmentedControl.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor)
topConstraint.active = true
leadingConstraint.active = true
trailingConstraint.active = true
}
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.requestWhenInUseAuthorization()
mapView.delegate = self
mapView.showsUserLocation = true
print("Is User Location Visible: \(mapView.userLocation.location?.coordinate.latitude)")
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
print("Authorization Status = \(CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse)")
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
locationManager.delegate = self
}
else{
print("location services disabled")
}
}
func mapTypeChanged(segControl: UISegmentedControl) {
switch segControl.selectedSegmentIndex {
case 0:
mapView.mapType = .Standard
case 1:
mapView.mapType = .Hybrid
case 2:
mapView.mapType = .Satellite
case 3:
zoomOnLocation()
default:
break
}
}
//Zoom to last known location
func zoomOnLocation() {
print("locations = \(self.mapView.userLocation.coordinate.longitude) ")
var location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(self.mapView.userLocation.coordinate.latitude, self.mapView.userLocation.coordinate.longitude)
var region:MKCoordinateRegion = MKCoordinateRegionMake(location, MKCoordinateSpanMake(0.5, 0.5))
print("zooming")
mapView.setRegion(region, animated: true)
}
//Delegate if Location has Changed
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
var locValue:CLLocationCoordinate2D = manager.location!.coordinate
print("locations = \(locValue.latitude) \(locValue.longitude)")
}
//Delegate if Authorization Status has Changed
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus){
locationManager.startUpdatingLocation()
}
func mapView(mapView: MKMapView!, didUpdateUserLocation userLocation: MKUserLocation!){
let coord = userLocation.coordinate
print("delegate: coord = \(coord.longitude)")
}
func mapViewDidFinishLoadingMap(mapView: MKMapView!){
print("finished loading mapview")
self.mapView.showsUserLocation = true
print("Is User Location Visible: \(self.mapView.userLocationVisible)")
}
func mapView(mapView: MKMapView!, mapViewWillStartLocatingUser userLocation: MKUserLocation!){
let coord = userLocation.coordinate
print("delegate: coord = \(coord.longitude)")
}
}

Using MKDirections to get Map Directions and Routes not working

i am trying to provide the user with a navigation direction with the click of a button. But for some reason it doesn't seem to be working.
#IBAction func directionToDestination(sender: AnyObject) {
getDirections()
}
func getDirections(){
let request = MKDirectionsRequest()
let destination = MKPlacemark(coordinate: CLLocationCoordinate2DMake(place.latitude, place.longitude), addressDictionary: nil)
request.setSource(MKMapItem.mapItemForCurrentLocation())
request.setDestination(MKMapItem(placemark: destination))
request.transportType = MKDirectionsTransportType.Automobile
var directions = MKDirections(request: request)
directions.calculateDirectionsWithCompletionHandler({(response:
MKDirectionsResponse!, error: NSError!) in
if error != nil {
// Handle error
} else {
self.showRoute(response)
}
})
}
func showRoute(response: MKDirectionsResponse) {
for route in response.routes as! [MKRoute] {
placeMap.addOverlay(route.polyline,level: MKOverlayLevel.AboveRoads)
for step in route.steps {
println(step.instructions)
}
}
}
func mapView(mapView: MKMapView!, rendererForOverlay
overlay: MKOverlay!) -> MKOverlayRenderer! {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = UIColor.blueColor()
renderer.lineWidth = 5.0
return renderer
}
here is how my viewDidLoad() looks
manager = CLLocationManager()
manager.delegate = self
manager.requestWhenInUseAuthorization()
placeMap.delegate = self
can someone please point what am i doing wrong with a sample code in swift ?
Here is a full working sample for getting the users location and getting directions to a destination coordinate.
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.showsUserLocation = true
mapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
#IBAction func directionToDestinationButtonPressed(_ sender: UIButton) {
guard let userLocationCoordinate = UserLocation.shared.location?.coordinate else { return }
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(
placemark: MKPlacemark(
coordinate: userLocationCoordinate
)
)
directionRequest.destination = MKMapItem(
placemark: MKPlacemark(
coordinate: CLLocationCoordinate2D(latitude: 47.6205, longitude: -122.3493)
)
)
directionRequest.transportType = .automobile
let directions = MKDirections(request: directionRequest)
directions.calculate { (response, error) in
guard let response = response else { return }
let route = response.routes.first
if let line = route?.polyline {
self.mapView.addOverlay(line, level: .aboveRoads)
}
}
}
//MARK: - MKMapViewDelegate
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let polyLine = overlay as? MKPolyline {
let lineRenderer = MKPolylineRenderer(polyline: polyLine)
lineRenderer.strokeColor = .red
lineRenderer.lineWidth = 3
return lineRenderer
}
return MKOverlayRenderer()
}
//MARK: - CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
UserLocation.shared.location = locations.first
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .authorizedWhenInUse:
locationManager.startUpdatingLocation()
locationManager.startUpdatingHeading()
case .denied:
UserLocation.shared.location = nil
locationManager.requestWhenInUseAuthorization()
case .notDetermined:
UserLocation.shared.location = nil
locationManager.requestWhenInUseAuthorization()
default:
break
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Location Manager Error -> \(String(describing: error.localizedDescription))")
}
}
Add this class to hold the users location
class UserLocation {
static let shared = UserLocation()
var location: CLLocation?
}
In the Info.plist add this key and value
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location Usage Description Shown To The User</string>
I don't know if you added the two required strings into the plist project.
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription

Resources