51

I am learning how to use the new Swift language (only Swift, no Objective-C). To do it, I want to do a simple view with a map (MKMapView). I want to find and update the location of the user (like in the Apple Map app).

I tried this, but nothing happened:

import MapKit
import CoreLocation

class MapView : UIViewController, CLLocationManagerDelegate {

    @IBOutlet weak var map: MKMapView!
    var locationManager: CLLocationManager!

    override func viewDidLoad() {
        super.viewDidLoad()

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

Could you please help me?

Kuldeep
  • 4,466
  • 8
  • 32
  • 59
PMIW
  • 757
  • 2
  • 7
  • 15
  • Simple go through this link: https://stackoverflow.com/questions/25449469/show-current-location-and-update-location-in-mkmapview-in-swift/49191349#49191349 – Mr.Javed Multani Mar 09 '18 at 10:13

11 Answers11

81

You have to override CLLocationManager.didUpdateLocations (part of CLLocationManagerDelegate) to get notified when the location manager retrieves the current location:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if let location = locations.last{
        let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
        let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
        self.map.setRegion(region, animated: true)
    }
}

NOTE: If your target is iOS 8 or above, you must include the NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key in your Info.plist to get the location services to work.

Chanchal Raj
  • 4,176
  • 4
  • 39
  • 46
zisoft
  • 22,770
  • 10
  • 62
  • 73
  • Thanks for your answer Zisoft. But, to use the function, I have to "save" all my new locations in a kind of list ? Then, is `startUpdatingLocation()` suffisant to update the location ? NOTE: Euh... sorry but how can I do it please ? :s Thank you very much ! – PMIW Aug 22 '14 at 17:44
  • After you have called `startUpdatingLocation` once, `didUpdateLocations` is fired everytime a location change is detected. You can do whatever you need with the location, i.e. store it in an array to draw a path on the map view. – zisoft Aug 22 '14 at 17:55
  • ok thanks. And how can I include the `NSLocationAlwaysUsageDescription` key in my Info.plist please ? – PMIW Aug 22 '14 at 19:40
  • In XCode, click on Info.plist and add a new row. Use `NSLocationAlwaysUsageDescription` as the key and the text you want to present to the user as value (String). – zisoft Aug 22 '14 at 20:22
  • The value should be a string. This text is displayed by the system when it asks the user for permission to use the location services. This is mandatory in iOS 8. – zisoft Aug 22 '14 at 20:31
  • Just a comment to the answer : We can not use `.last`for an array, so I used `array[count-1]` – PMIW Aug 23 '14 at 08:33
  • You can use array.last as of XCode 6 Beta 5. – zisoft Aug 23 '14 at 08:50
  • I'd recommend using NSLocationWhenInUseUsageDescription if you only need to track the user's location when the app is running. People are more likely to click "Accept" that way – Toddarooski Apr 10 '15 at 16:57
  • Do you know how to do it with GoogleMaps? Because self.map.setRegion(region, animated: true) can't work in a GoogleMaps mapView –  Oct 02 '17 at 09:56
39

100% working, easy steps and tested

Import libraries:

import MapKit
import CoreLocation

set delegates:

CLLocationManagerDelegate,MKMapViewDelegate

Take variable:

let locationManager = CLLocationManager()

write this code on viewDidLoad():

self.locationManager.requestAlwaysAuthorization()

    // For use in foreground
    self.locationManager.requestWhenInUseAuthorization()

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

    mapView.delegate = self
    mapView.mapType = .standard
    mapView.isZoomEnabled = true
    mapView.isScrollEnabled = true

    if let coor = mapView.userLocation.location?.coordinate{
        mapView.setCenter(coor, animated: true)
    }

Write delegate method for location:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let locValue:CLLocationCoordinate2D = manager.location!.coordinate

    mapView.mapType = MKMapType.standard

    let span = MKCoordinateSpanMake(0.05, 0.05)
    let region = MKCoordinateRegion(center: locValue, span: span)
    mapView.setRegion(region, animated: true)

    let annotation = MKPointAnnotation()
    annotation.coordinate = locValue
    annotation.title = "Javed Multani"
    annotation.subtitle = "current location"
    mapView.addAnnotation(annotation)

    //centerMap(locValue)
}

Do not forgot to set permission in info.plist

<key>NSLocationWhenInUseUsageDescription</key>
<string>This application requires location services to work</string>

<key>NSLocationAlwaysUsageDescription</key>
<string>This application requires location services to work</string>

It's look like:

enter image description here

Adrian P
  • 6,479
  • 4
  • 38
  • 55
Mr.Javed Multani
  • 12,549
  • 4
  • 53
  • 52
21

For swift 3 and XCode 8 I find this answer:

  • First, you need set privacy into info.plist. Insert string NSLocationWhenInUseUsageDescription with your description why you want get user location. For example, set string "For map in application".

  • Second, use this code example

    @IBOutlet weak var mapView: MKMapView!
    
    private var locationManager: CLLocationManager!
    private var currentLocation: CLLocation?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        mapView.delegate = self
    
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
    
        // Check for Location Services
    
        if CLLocationManager.locationServicesEnabled() {
            locationManager.requestWhenInUseAuthorization()
            locationManager.startUpdatingLocation()
        }
    }
    
    // MARK - CLLocationManagerDelegate
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        defer { currentLocation = locations.last }
    
        if currentLocation == nil {
            // Zoom to user location
            if let userLocation = locations.last {
                let viewRegion = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 2000, 2000)
                mapView.setRegion(viewRegion, animated: false)
            }
        }
    }
    
  • Third, set User Location flag in storyboard for mapView.

Evgeny Karev
  • 605
  • 6
  • 13
7

MyLocation is a Swift iOS Demo.

You can use this demo for the following:

  1. Show the current location.

  2. Choose other location: in this case stop tracking the location.

  3. Add a push pin to a MKMapView(iOS) when touching.

Ahmed Lotfy
  • 3,806
  • 26
  • 28
  • 3
    Please don't add the same answer to multiple questions. Answer the best one and flag the rest as duplicates. See [Is it acceptable to add a duplicate answer to several questions?](http://meta.stackexchange.com/q/104227) – Bhargav Rao Jun 09 '16 at 12:18
  • Thanks, I will do that – Ahmed Lotfy Jun 09 '16 at 13:22
5

Hi Sometimes setting the showsUserLocation in code doesn't work for some weird reason.

So try a combination of the following.

In viewDidLoad()

  self.mapView.showsUserLocation = true

Go to your storyboard in Xcode, on the right panel's attribute inspector tick the User location check box, like in the attached image. run your app and you should be able to see the User location

enter image description here

GyroCocoa
  • 1,542
  • 16
  • 19
5

Swift 5.1

Get Current Location and Set on MKMapView

Import libraries:

import MapKit
import CoreLocation

set delegates:

CLLocationManagerDelegate , MKMapViewDelegate

Declare variable:

let locationManager = CLLocationManager()

Write this code on viewDidLoad():

self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()

if CLLocationManager.locationServicesEnabled() {
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.startUpdatingLocation()
}
mapView.delegate = self
mapView.mapType = .standard
mapView.isZoomEnabled = true
mapView.isScrollEnabled = true

if let coor = mapView.userLocation.location?.coordinate{
    mapView.setCenter(coor, animated: true)
}

Write delegate method for location:

func locationManager(_ manager: CLLocationManager, didUpdateLocations 
    locations: [CLLocation]) {
    let locValue:CLLocationCoordinate2D = manager.location!.coordinate

    mapView.mapType = MKMapType.standard

    let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
    let region = MKCoordinateRegion(center: locValue, span: span)
    mapView.setRegion(region, animated: true)

    let annotation = MKPointAnnotation()
    annotation.coordinate = locValue
    annotation.title = "You are Here"
    mapView.addAnnotation(annotation)
}

Set permission in info.plist *

<key>NSLocationWhenInUseUsageDescription</key>
<string>This application requires location services to work</string>

<key>NSLocationAlwaysUsageDescription</key>
<string>This application requires location services to work</string>
Matt Ke
  • 3,599
  • 12
  • 30
  • 49
Raksha.
  • 479
  • 6
  • 6
3

For Swift 2, you should change it to the following:

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let location = locations.last

    let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
    let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))

    self.map.setRegion(region, animated: true)
}
Mark
  • 85
  • 1
  • 11
2

You just need to set the userTrackingMode of the MKMapView. If you only want to display and track the user location and implement the same behaviour as the Apple Maps app uses, there is no reason for writing additional code.

mapView.userTrackingMode = .follow

See more at https://developer.apple.com/documentation/mapkit/mkmapview/1616208-usertrackingmode .

Vincent Friedrich
  • 1,027
  • 1
  • 8
  • 11
1

you have to override CLLocationManager.didUpdateLocations

 func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

    let userLocation:CLLocation = locations[0] as CLLocation
    locationManager.stopUpdatingLocation()

    let location = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude, longitude: userLocation.coordinate.longitude)

    let span = MKCoordinateSpanMake(0.5, 0.5)

    let region = MKCoordinateRegion (center:  location,span: span)

    mapView.setRegion(region, animated: true)
}

you also have to add NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription to your plist setting Result as value

MiladiuM
  • 1,449
  • 16
  • 17
1

In Swift 4, I had used the locationManager delegate function as defined above ..

func locationManager(manager: CLLocationManager!, 
    didUpdateLocations locations: [AnyObject]!) {

.. but this needed to be changed to ..

func locationManager(_ manager: CLLocationManager,
    didUpdateLocations locations: [CLLocation]) {

This came from .. https://github.com/lotfyahmed/MyLocation/blob/master/MyLocation/ViewController.swift - thanks!

Tybion
  • 87
  • 1
  • 7
0
mapView.showsUserLocation = true

Create UIButton and add this action

@IBAction func showCurrentLocation(_ sender: Any) {
        let coordinate = mapView.userLocation.coordinate
        let center = CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude)
        let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
        self.mapView.setRegion(region, animated: true)
    }
zsyesenko
  • 700
  • 6
  • 8