locate user location in Swift - ios

I try to add Current Location in to the map by using CLLocationmanager, but when I try to call the func mapView.StartUpdateLocation some how the delegate protocol " didUpdateLocation " is not to be called, any know how can I fix this ? Thanks
import UIKit
import MapKit
class mapViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet var mapView: MKMapView!
var restaurant:Restaurant!
var locationManager = CLLocationManager()
var current: CLPlacemark!
override func viewDidLoad()
{
super.viewDidLoad()
mapView.delegate = self
self.locationManager.requestAlwaysAuthorization()
// convert address to coordinate
let geoCoder = CLGeocoder()
geoCoder.geocodeAddressString(restaurant.location, completionHandler: { (placemarks, error) -> Void in
if error != nil
{
print(error)
return
}
if placemarks.count > 0
{
let placemark = placemarks[0] as CLPlacemark
// add annotation
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.location.coordinate
annotation.title = self.restaurant.name
annotation.subtitle = self.restaurant.type
self.mapView.showAnnotations([annotation], animated: true)
self.mapView.selectAnnotation(annotation, animated: true)
self.mapView.showsUserLocation = true // add to show user location
}
})
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func currentLocation(sender: AnyObject)
{
if ( CLLocationManager.locationServicesEnabled())
{
println("Location service is on ")
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.stopUpdatingLocation()
locationManager.startUpdatingLocation()
}else
{
println("Location service is not on ")
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
{
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: { (placemarks, error) -> Void in
if error != nil
{
print("error")
}
if placemarks.count > 0
{
self.current = placemarks[0] as CLPlacemark
let annotation = MKPointAnnotation()
annotation.coordinate = self.current.location.coordinate
self.mapView.showAnnotations([annotation], animated: true)
self.mapView.selectAnnotation(annotation, animated: true)
}
else
{
print("I dont know what the fuck is the error")
}
})
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println(error.localizedDescription)
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView!
{
let indentifier = "My Pin"
if annotation.isKindOfClass(MKUserLocation){ return nil }
// Resuse Annotation if possiable
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(indentifier)
if annotationView == nil
{
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: indentifier)
annotationView.canShowCallout = true // tell annotation can display
}
let iconImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 53, height: 53)) // create left icon image for annotation view
iconImageView.image = UIImage(named: restaurant.image)
annotationView.leftCalloutAccessoryView = iconImageView
return annotationView
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}

There is a change between iOS7 & 8 about GPS localisation. Please read this article.
http://matthewfecher.com/app-developement/getting-gps-location-using-core-location-in-ios-8-vs-ios-7/
Maybe you have not added these infos to your .plist
<key>NSLocationAlwaysUsageDescription</key>
<string>Your message goes here</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your message goes here</string>

Please check once below keys entered in info.plist
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
and set
var _locationManager = CLLocationManager()
_locationManager.delegate = self
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
_locationManager.requestAlwaysAuthorization()
in viewDidLoad()

Related

Timer is not allowing to add annotation on mapView in iOS swift

I have a situation where I have to call an API to fetch some Vehicles Locations objects in an array after getting the user current location. After fetching vehicles, I have to get the address also from Vehicles Locations data, so for 'n' Vehicles, there will be an 'n' API call and then add annotations on Map.
After that, I have to refresh the Vehicles data every 1 min. So, I created a timer but even after getting the API response, annotations are not displaying on map. Kindly look into this issue.
Below is Map View
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet private var mapView: MKMapView!
var currentLocation: CLLocation?
var user: User?
lazy var vehicleViewModel = {
VehicleViewModel()
}()
var locationUpdateTimer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
configureLocationManager()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
stopTimer()
}
func configureLocationManager() {
LocationManager.shared().delegate = self
LocationManager.shared().initializeLocationManager()
}
func configureTimer() {
if locationUpdateTimer == nil {
locationUpdateTimer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(runLocationTimer), userInfo: nil, repeats: true)
}
}
#objc func runLocationTimer() {
fetchVehiclesLocation()
}
func resetMap() {
let annotations = mapView.annotations
mapView.removeAnnotations(annotations)
mapView = nil
}
func initializeMapView() {
mapView = MKMapView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height))
mapView.delegate = self
}
func configureMapView() {
let mapDetail = vehicleViewModel.getLatitudeLongitudeLatitudeDeltaLongitudeDelta()
if let latitude = mapDetail.0, let longitude = mapDetail.1, let latitudeDelta = mapDetail.2, let longitudeDelta = mapDetail.3 {
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: latitude, longitude: longitude), latitudinalMeters: latitudeDelta, longitudinalMeters: longitudeDelta)
let scaledRegion: MKCoordinateRegion = mapView.regionThatFits(region)
mapView.setRegion(scaledRegion, animated: true)
mapView.setCameraBoundary(
MKMapView.CameraBoundary(coordinateRegion: region),
animated: true)
let zoomRange = MKMapView.CameraZoomRange(maxCenterCoordinateDistance: 100000)
mapView.setCameraZoomRange(zoomRange, animated: true)
mapView.register(
VehicleAnnotationView.self,
forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
}
}
func fetchVehiclesLocation() {
configureTimer()
initViewModel {
DispatchQueue.main.async {
self.resetMap()
self.initializeMapView()
self.configureMapView()
}
if let user = self.user {
self.vehicleViewModel.fetchVehicleAddress(user: user, completion: { status in
if self.vehicleViewModel.vehicleAnnotationItems.count == 0 {
self.alertWithTitleAndMessageWithOK(("Alert" , "error while fetching vehicle locations"))
} else {
DispatchQueue.main.async {
self.mapView.addAnnotations(self.vehicleViewModel.vehicleAnnotationItems)
}
}
})
}
}
}
func initViewModel(completion: #escaping () -> Void) {
if let user = self.user, let userId = user.userId {
vehicleViewModel.getVehiclesLocation(userId: userId) { (vehicleApiResponse, error) in
if vehicleApiResponse != nil {
completion()
} else {
self.alertWithTitleAndMessageWithOK(("Alert" , error?.localizedDescription ?? "error while fetching vehicles"))
}
}
}
}
func stopTimer() {
if locationUpdateTimer != nil {
locationUpdateTimer!.invalidate()
locationUpdateTimer = nil
}
}
deinit {
stopTimer()
}
}
//MARK: - LocationManagerDelegate methods
extension MapViewController: LocationManagerDelegate {
func didFindCurrentLocation(_ location: CLLocation) {
currentLocation = location
if let currentLocation = currentLocation, (currentLocation.horizontalAccuracy >= 0) {
mapView.showsUserLocation = true
fetchVehiclesLocation()
}
}
}
LocationManager Extension class
import CoreLocation
protocol LocationManagerDelegate: AnyObject {
func didFindCurrentLocation(_ location: CLLocation)
func didFailedToFindCurrentLocationWithError(_ error: NSError?)
func alertLocationAccessNeeded()
}
/**
This class acts as a Singleton for getting location manager updates across the application.
*/
class LocationManager: NSObject {
var manager: CLLocationManager!
private static var sharedNetworkManager: LocationManager = {
let networkManager = LocationManager()
return networkManager
}()
private override init() {
super.init()
manager = CLLocationManager()
}
class func shared() -> LocationManager {
return sharedNetworkManager
}
weak var delegate: LocationManagerDelegate?
//Entry point to Location Manager. First the initialization has to be done
func initializeLocationManager() {
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.distanceFilter = kCLDistanceFilterNone
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.allowsBackgroundLocationUpdates = false
startUpdating()
}
//Start updating locations
func startUpdating() {
manager.startUpdatingLocation()
}
//Check for whether location services are disabled.
func locationServicesEnabled() -> Bool {
let isAllowed = CLLocationManager.locationServicesEnabled()
return isAllowed
}
}
//MARK: - CLLocation Manager delegate methods
extension LocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else {
return
}
manager.stopUpdatingLocation()
delegate?.didFindCurrentLocation(location)
// manager.delegate = nil
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
delegate?.didFailedToFindCurrentLocationWithError(error as NSError?)
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .notDetermined:
self.manager.requestWhenInUseAuthorization()
break
case .authorizedWhenInUse, .authorizedAlways:
if locationServicesEnabled() {
self.startUpdating()
}
case .restricted, .denied:
delegate?.alertLocationAccessNeeded()
#unknown default:
print("Didn't request permission for location access")
}
}
}
Your code has a number of problems.
Neither your initializeMapView() function nor your resetMap() function make any sense.
You should add an MKMapView to your Storyboard, then connect it to your mapView outlet, and then don't assign a new value to mapView. Don't set it to nil, and don't replace the map view in the outlet with a brand new map view you create (like you're doing in initializeMapView().) Both of those things will prevent your map from displaying.
You also never create a timer except in your fetchVehiclesLocation() function, which doesn't seem right.
You also don't show how you're setting up your location manager and asking for location updates. (You call a function initializeLocationManager(). I don't believe that is an Apple-provided function. I'm guessing you added it in an extension to the location manager, but you don't show that code.)
You need to ask if the user has granted permission to use the location manager, and trigger a request for permission if not.
Once you have permission to use the location manager, you need to ask it to start updating the user's location.
You don't show any of that code.
Maybe you're doing that in code you didn't show? It also looks like you don't have your CLLocationManagerDelegate methods defined correctly. I don't know of any delegate method didFindCurrentLocation(_:). You will likely need to implement one of the delegate methods locationManager(_:didUpdateLocations:) or locationManager(_:didUpdateTo:from:).
I suggest searching for a tutorial on using the location manager to display the user's location on a map. It's a little involved, and requires some study to set up.

Location is working but its not tracking my distrance travelled in Swift 3

I'm making an app for one of my courses. It is supposed to track the distance traveled and update a label to show how far they've gone. When I open the app it asks for permission to track location. The mapView works, it follows the location but the label is never updated to show the distance traveled. I've added my code below, any help is greatly appreciated!
//
// ViewController.swift
// location_tracker
//
// Created by Dale McCaughan on 2016-10-19.
// Copyright © 2016 Dale McCaughan. All rights reserved.
//
import UIKit
import CoreLocation
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var theMap: MKMapView!
#IBOutlet weak var l: UILabel!
let locationManager = CLLocationManager()
var startLocation: CLLocation!
var monitoredRegions: Dictionary<String, NSDate> = [:]
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.isNavigationBarHidden = true
self.navigationController?.isToolbarHidden = false;
//Status bar style and visibility
UIApplication.shared.statusBarStyle = .lightContent
//Change status bar color
let statusBar: UIView = UIApplication.shared.value(forKey: "statusBar") as! UIView
//if statusBar.respondsToSelector("setBackgroundColor:") {
statusBar.backgroundColor = UIColor.white
//}
UIToolbar.appearance().backgroundColor = UIColor.white
}
override func viewDidLoad() {
super.viewDidLoad()
//Setup the Location Manager
locationManager.delegate = self;
locationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
//Setup the Map View
theMap.delegate = self
theMap.showsUserLocation = true
theMap.userTrackingMode = .follow
// setup test data
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// status is not determined
if CLLocationManager.authorizationStatus() == .notDetermined {
locationManager.requestAlwaysAuthorization()
}
// authorization were denied
else if CLLocationManager.authorizationStatus() == .denied {
showAlert("Location services were previously denied. Please enable location services for this app in Settings.")
}
// we do have authorization
else if CLLocationManager.authorizationStatus() == .authorizedAlways {
locationManager.startUpdatingLocation()
}
}
// MARK: - MKMapViewDelegate
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let circleRenderer = MKCircleRenderer(overlay: overlay)
circleRenderer.strokeColor = UIColor.red
circleRenderer.lineWidth = 1.0
return circleRenderer
}
#IBAction func resetDistance(_ sender: AnyObject) {
startLocation = nil
}
// MARK: - CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
showAlert("enter \(region.identifier)")
monitoredRegions[region.identifier] = Date() as NSDate?
l.text = "in location manager1"
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
showAlert("exit \(region.identifier)")
monitoredRegions.removeValue(forKey: region.identifier)
l.text = "in location manager2"
}
var lastLocation: CLLocation!
var traveledDistance:Double = 0
func locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject]) {
if let firstLocation = locations.first as? CLLocation
{
theMap.setCenter(firstLocation.coordinate, animated: true)
let region = MKCoordinateRegionMakeWithDistance(firstLocation.coordinate, 1000, 1000)
theMap.setRegion(region, animated: true)
if let oldLocation = lastLocation {
let delta: CLLocationDistance = firstLocation.distance(from: lastLocation)
traveledDistance += delta
}
lastLocation = firstLocation
}
l.text = String(format: "%.3f", traveledDistance/1000) + " kilometers"
}
// MARK: - Helpers
func showAlert(_ title: String) {
let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Try this:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let firstLocation = locations.first
The delegate signature that you were using wasn't quite what the delegate was looking for. With the signature corrected, you don't need the as CLLocation cast anymore.
I verified that it works with that change. For future reference, you could set a breakpoint at didUpdateLocations and you would see right away that it wasn't getting called and then work backwards from there.
Also make sure that Info.plist contains all the necessary location-related Privacy strings (I usually just put in all three to cover all the bases).

make pin draggable and long click

I've been trying for hours to make the pin draggable in MapKit, but it seems that the pin is so stubborn it didn't want to move.
this is my code:
import UIKit
import MapKit
protocol AddCoffeeDelegate {
func viewController(vc: AddCoffeeViewController, didAddCoffee coffee : Coffee! )
}
class AddCoffeeViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet var mapView: MKMapView!
#IBOutlet weak var coffeeName: UITextField!
#IBOutlet weak var coffeeRating: UITextField!
var coffee: Coffee?
var delegate: AddCoffeeDelegate?
////////////////////////////////////////////////////
var coreLocationManager = CLLocationManager()
var locationManager : LocationManager!
var savedLocation : CLLocation?
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKPointAnnotation {
let pinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "myPin")
pinAnnotationView.pinTintColor = UIColor.redColor()
pinAnnotationView.draggable = true
pinAnnotationView.canShowCallout = false
pinAnnotationView.animatesDrop = true
return pinAnnotationView
}
return nil
}
func getLocation(){
locationManager.startUpdatingLocationWithCompletionHandler { (latitude, longitude, status, verboseMessage, error) -> () in
self.displayLocation(CLLocation(latitude: latitude, longitude: longitude))
}
}
func displayLocation(location: CLLocation){
mapView.setRegion(MKCoordinateRegion(center: CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude), span: MKCoordinateSpanMake(0.05, 0.05)), animated: true)
let locationPinCoord = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let annotation = MKPointAnnotation()
annotation.title = "My Title"
annotation.subtitle = "My Subtitle"
annotation.coordinate = locationPinCoord
mapView.addAnnotation(annotation)
savedLocation = location
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status != CLAuthorizationStatus.NotDetermined || status != CLAuthorizationStatus.Denied || status != CLAuthorizationStatus.Restricted {
getLocation()
}
}
////////////////////////////////////////////////////
override func viewDidLoad() {
super.viewDidLoad()
coreLocationManager.delegate = self
locationManager = LocationManager.sharedInstance
let authorizationCode = CLLocationManager.authorizationStatus()
if authorizationCode == CLAuthorizationStatus.NotDetermined && coreLocationManager.respondsToSelector("requestAlwaysAuthorization") || coreLocationManager.respondsToSelector("requestWhenInUseAuthorization"){
if NSBundle.mainBundle().objectForInfoDictionaryKey("NSLocationAlwaysUsageDescription") != nil {
coreLocationManager.requestAlwaysAuthorization()
}else{
print("no desscription provided ")
}
}else{
getLocation()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func cancel(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func save(sender: AnyObject) {
var createdCoffee = Coffee()
createdCoffee.name = self.coffeeName.text!
createdCoffee.rating = Double(self.coffeeRating.text!)!
createdCoffee.place = savedLocation
self.coffee = createdCoffee
self.delegate?.viewController(self, didAddCoffee: self.coffee)
}
}
I have tried every related issue with mapkit in swift, but it seems that the pin won't drag itself.Where could the problem be? I have already set the title and implement the MKMapViewDelegate protocol, but still it wont drag.
Did you set the delegate of the mapview to the view controller either in code, or via the Storyboard?
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
...
}

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

How to Stop getting the users location in MapBox

How can you stop getting the user location when using CLLocationManager and mapbox?
I have a application that does the following:
1) Gets the users current location with the CLLocationManager and then calls the command ".stopUpdatingLocation()" which stops getting the user location.
2) Creates a map with mapbox
As soon as the application has both, it does NOT stop getting the user location.
I tested the application in the each separate scenarios (option 1 above alone and option 2 alone) and it successfully stop getting the user location but when the application has both implemented it does NOT stop getting the user location.
viewController.swift:
import UIKit
import MapboxGL
import CoreLocation
class ViewController: UIViewController, MGLMapViewDelegate , CLLocationManagerDelegate {
//MARK: - Properties
var manager: CLLocationManager?
private var currentLocation: CLPlacemark?
private var currLocLatitude:CLLocationDegrees?
private var currLocLongitude:CLLocationDegrees?
private var currLocTitle:String?
private var currLocSubtitle:String?
private var MapBoxAccessToken = "AccessToken.GoesHere"
//MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
manager = CLLocationManager()
manager?.delegate = self
manager?.desiredAccuracy = kCLLocationAccuracyBest
manager?.requestWhenInUseAuthorization()
manager?.startUpdatingLocation()
}
//MARK: - Helper
/* gather location information */
func getLocationInfo(placemark: CLPlacemark) {
currentLocation = placemark //will delete later - redudant
currLocLatitude = placemark.location.coordinate.latitude
currLocLongitude = placemark.location.coordinate.longitude
currLocTitle = placemark.areasOfInterest[0] as? String
currLocSubtitle = placemark.locality
//DEBUGGING
print(placemark.location.coordinate.latitude)
print(placemark.location.coordinate.longitude)
print(placemark.areasOfInterest[0])
print(placemark.locality)
}
//MARK: - CLLocationManagerDelegate
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
manager.stopUpdatingLocation()
let location = locations[0] as? CLLocation
let geoCoder = CLGeocoder()
geoCoder.reverseGeocodeLocation(manager.location, completionHandler: {(placemarks, error) -> Void in
if (error != nil) {
println("ERROR:" + error.localizedDescription)
return
}
if placemarks.count > 0 {
var currLocation = placemarks[0] as! CLPlacemark
self.getLocationInfo(currLocation)
self.createMapBoxMap()
} else {
print("Error with data")
}
})
}
func locationManager( manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
print(" Authorization status changed to \(status.rawValue)")
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError) {
print("Error:" + error.localizedDescription)
}
//MARK: - MapBox Methods
private func createMapBoxMap(){
//type of map style
let mapView = MGLMapView(frame: view.bounds, accessToken: MapBoxAccessToken)
//dark map style
// let mapView = MGLMapView(frame: view.bounds, accessToken: "pk.eyJ1IjoibHVvYW5kcmUyOSIsImEiOiI4YzAyOGMwOTAwMmQ4M2U5MTA0YjliMjgxM2RiYzk0NSJ9.isuNZriXdmrh-n9flwTY9g",styleURL: NSURL(string: "asset://styles/dark-v7.json"))
mapView.autoresizingMask = .FlexibleWidth | .FlexibleHeight
//setting the map's center coordinate
mapView.setCenterCoordinate(CLLocationCoordinate2D(latitude: currLocLatitude!, longitude: currLocLongitude!),
zoomLevel: 25, animated: false)
view.addSubview(mapView)
/*define the marker and its coordinates, title, and subtitle:*/
mapView.delegate = self // Set the delegate property of our map view to self after instantiating it.
// Declare the marker `ellipse` and set its coordinates, title, and subtitle
let ellipse = MyAnnotation(location: CLLocationCoordinate2D(latitude: currLocLatitude!, longitude: currLocLongitude!),
title: currLocTitle!, subtitle: currLocSubtitle!)
mapView.addAnnotation(ellipse) // Add marker `ellipse` to the map
}
//MARK: - MGLMapViewDelegate
/* defining the marker from MyAnnotation.swift */
func mapView(mapView: MGLMapView!, symbolNameForAnnotation annotation: MGLAnnotation!) -> String! {
return "secondary_marker"
}
/* Tapping the marker */
func mapView(mapView: MGLMapView!, annotationCanShowCallout annotation: MGLAnnotation!) -> Bool {
return true
}
}
AppDelegate.swift:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
}
MyAnnotation.swift:
import Foundation
import MapboxGL
class MyAnnotation: NSObject, MGLAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String!
var subtitle: String!
init(location coordinate: CLLocationCoordinate2D, title: String, subtitle: String) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
}
}
You are calling the manager returned in the function, try call self.manager.stopUpdatingLocation()
Resolved this issue by getting the user location inside the "ViewDidLoad" method and creating the map inside the "ViewDidAppear" method
By having them seperated, it seems to have resolve the problem.
import UIKit
import CoreLocation
import MapboxGL
class AViewController: UIViewController, CLLocationManagerDelegate {
var manager:CLLocationManager!
var userLocation:CLLocation!
override func viewDidLoad() {
super.viewDidLoad()
getUserLocation()
}//eom
override func viewDidAppear(animated: Bool) {
createMapBoxMap()
}
/*getting user current location*/
func getUserLocation(){
self.manager = CLLocationManager()
self.manager.delegate = self
self.manager.desiredAccuracy = kCLLocationAccuracyBest
self.manager.requestWhenInUseAuthorization()
self.manager.startUpdatingLocation()
}//eom
/*location manager 'didUpdateLocations' function */
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
self.manager.stopUpdatingLocation() //stop getting user location
println(locations)
self.userLocation = locations[0] as! CLLocation
}//eom
/*Create preliminary map */
func createMapBoxMap(){
// set your access token
let mapView = MGLMapView(frame: view.bounds, accessToken: "pk.eyJ1IjoiZGFya2ZhZGVyIiwiYSI6IlplVDhfR3MifQ.pPEz732qS8g0WEScdItakg")
mapView.autoresizingMask = .FlexibleWidth | .FlexibleHeight
// set the map's center coordinate
mapView.setCenterCoordinate(CLLocationCoordinate2D(latitude: self.userLocation.coordinate.latitude, longitude: self.userLocation.coordinate.longitude),
zoomLevel: 13, animated: false)
view.addSubview(mapView)
//showing the user location on map - blue dot
mapView.showsUserLocation = true
}//eom

Resources