How to get current longitude and latitude using CLLocationManager-Swift
Asked Answered
I

10

45

I want to get the current longitude and latitude of a location using Swift and display them via labels. I tried to do this but nothing displays on the labels.

import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate{

    @IBOutlet weak var longitude: UILabel!
    @IBOutlet weak var latitude: UILabel!
    let locationManager = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        if (CLLocationManager.locationServicesEnabled()) {
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.requestWhenInUseAuthorization()
            locationManager.startUpdatingLocation()
        } else {
            println("Location services are not enabled");
        }
    }

    // MARK: - CoreLocation Delegate Methods

    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
         locationManager.stopUpdatingLocation()
         removeLoadingView()
         if (error) != nil {
             print(error)
          }
     }

    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        var locationArray = locations as NSArray
        var locationObj = locationArray.lastObject as CLLocation
        var coord = locationObj.coordinate
        longitude.text = coord.longitude
        latitude.text = coord.latitude
        longitude.text = "\(coord.longitude)"
        latitude.text = "\(coord.latitude)"
    }
}
Indopacific answered 4/11, 2014 at 17:44 Comment(1)
possible duplicate of CLLocation Manager in Swift to get Location of UserBookcraft
B
86

IMHO, you are over complicating your code when the solution you are looking is pretty simple.

I have done it by using the following code:

First create an instance of CLLocationManager and Request Authorization

var locManager = CLLocationManager()
locManager.requestWhenInUseAuthorization()

then check if the user allowed authorization.

var currentLocation: CLLocation!

if 
   CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
   CLLocationManager.authorizationStatus() ==  .authorizedAlways
{         
    currentLocation = locManager.location        
}

to use it just do this

label1.text = "\(currentLocation.coordinate.longitude)"
label2.text = "\(currentLocation.coordinate.latitude)"

Your idea of setting them to the label.text is correct, however the only reason I can think of is that the user is not giving you permission and that is why your current Location data will be nil.

However you would need to debug and tell us that. Also the CLLocationManagerDelegate is not necessary.

Hopefully this helps. Ask away if you have doubts.

Boysenberry answered 4/11, 2014 at 19:3 Comment(7)
Where is your second code block supposed to go? In a delegate method?Quacksalver
i usually put it in "viewdidload" or "awakefromnib" but it can be used anywhere. it has no limitation as long as is asked the user permission to use their location and that he/she grants it.Boysenberry
I disagree with this advice. The code above isn't even starting the location manager - it's just making sure it's authorized. The location manager's current location reading is likely to be old and grossly inaccurate. When you activate the location manager and ask for location updates the first few location results tend to be very bad. You really do need to set up a delegate, start location updates, and check the accuracy readings on the location updates you get until they settle down.Carmoncarmona
@DuncanC be that as it may. Respecting your opinion, this code worked for me, I have it in production for an app I created for a Client. And more direct to the point, the OP asked for "Current Long Lat for a Location using Swift." Because apparently it was not working for him. This made it work apparently, like it did for me, thus answering his question. If you want to talk LocationManager Accuracy that my friend is another topic by itself.Boysenberry
Did not work for me when testing in xcode 9.1, in simulator, without delegate location was nil.Tenno
"import CoreLocation" is missing for importing allInkwell
@MadisMaenni I have the same problem with you. Is it still stuck or already get new solution?Pettifog
B
36

For Swift 3:

First you need to set allowance to receive User's GPS in the info.plist.

enter image description here

Set: NSLocationWhenInUseUsageDescription with a random String. And/or: NSLocationAlwaysUsageDescription with a random String.

Then:

import UIKit
import MapKit

class ViewController: UIViewController {

    var locManager = CLLocationManager()
    var currentLocation: CLLocation!

    override func viewDidLoad() {
        super.viewDidLoad()
        locManager.requestWhenInUseAuthorization()

        if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse ||
            CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways){
            guard let currentLocation = locManager.location else {
                return
            }
            print(currentLocation.coordinate.latitude)
            print(currentLocation.coordinate.longitude)
        }
    }
}

Done.

Brooke answered 9/11, 2016 at 20:48 Comment(9)
this code give me error on line "print(currentLocation.coordinate.latitude)"Reste
@BijenderSinghShekhawat yeah. please tell me WHAT error. howbowdah?Brooke
@MicroR , yes .Brooke
It uses the same sensorsBrooke
@DavidSeek for me it always going on guard statement it return. can you please help me on this?Vulnerable
@YogeshPatel I can help you, but I don't understand your problem. Can you create a little code example here: gist.github.com and comment the answer here so I can follow your problemBrooke
The prop authorizationStatus changed a bit for iOS 14. See https://mcmap.net/q/370192/-authorizationstatus-for-cllocationmanager-is-deprecated-on-ios-14/1359088Amend
@BijenderSinghShekhawat If it is crashing or throwing error on that line when running on simulator you have to mock locations by selecting location symbol located on the debugger window bar and select a mock location.Kelvin
@YogeshPatel Try it in a device and not in simulator.Surveying
T
16

Despite other advice you should use the CLLocationManagerDelegate to safely retrieve a location (without using it you may get null locations when the location manager doesn't have enough time to update). I strongly recommend wrapping the location manager code within a static shared helper (something along these lines):

class Locator: NSObject, CLLocationManagerDelegate {
    enum Result <T> {
      case .Success(T)
      case .Failure(ErrorType)
    }

    static let shared: Locator = Locator()

    typealias Callback = (Result <Locator>) -> Void

    var requests: Array <Callback> = Array <Callback>()

    var location: CLLocation? { return sharedLocationManager.location  }

    lazy var sharedLocationManager: CLLocationManager = {
        let newLocationmanager = CLLocationManager()
        newLocationmanager.delegate = self
        // ...
        return newLocationmanager
    }()

    // MARK: - Authorization

    class func authorize() { shared.authorize() }
    func authorize() { sharedLocationManager.requestWhenInUseAuthorization() }

    // MARK: - Helpers

    func locate(callback: Callback) {
        self.requests.append(callback)
        sharedLocationManager.startUpdatingLocation()
    }

    func reset() {
        self.requests = Array <Callback>()
        sharedLocationManager.stopUpdatingLocation()
    }

    // MARK: - Delegate

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        for request in self.requests { request(.Failure(error)) }
        self.reset()
    }

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: Array <CLLocation>) {
        for request in self.requests { request(.Success(self)) }
        self.reset()
    }

}

Then in view did load (or anywhere else you need to get the current location) run:

Locator.shared.locate { result in
  switch result {
  case .Success(locator):
    if let location = locator.location { /* ... */ }
  case .Failure(error):
    /* ... */
  }
}
Tourcoing answered 28/9, 2015 at 21:48 Comment(5)
I'm getting an error: "Generic type 'Result' nested in type 'Locator' is not allowed". I've never seen this error in Swift. Any suggestions on a fix?Tyrus
@ClayEllis do enum Result declaration out of class and it will work.Maculate
used as per instruction getting an error like: Use of unresolved identifier 'locator'. into UIViewController.Mayle
Not working in Swift 4 and Xcode 10, please check once and edit your answer.Soulier
Try adding let before locator and error. I hope it helps. Locator.shared.locate { (result) in switch result { case .success(let locator): break case .failure(let err): break } }Absurdity
F
3

In Swift

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

    //Labels outlets

    @IBOutlet var localityTxtField: UITextField!
    @IBOutlet var postalCodeTxtField: UITextField!
    @IBOutlet var aAreaTxtField: UITextField!
    @IBOutlet var countryTxtField: UITextField!

    let locationManager = CLLocationManager()

    //View Didload

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

     //Button Location

    @IBAction func findMyLocation(_ sender: AnyObject) {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)->Void in

            if (error != nil) {
                print("Reverse geocoder failed with error" + (error?.localizedDescription)!)
                return
            }

            if (placemarks?.count)! > 0 {

                print("placemarks",placemarks!)
                let pm = placemarks?[0]
                self.displayLocationInfo(pm)
            } else {
                print("Problem with the data received from geocoder")
            }
        })
    }

    func displayLocationInfo(_ placemark: CLPlacemark?) {
        if let containsPlacemark = placemark {

            print("your location is:-",containsPlacemark)
            //stop updating location to save battery life
            locationManager.stopUpdatingLocation()
            let locality = (containsPlacemark.locality != nil) ? containsPlacemark.locality : ""
            let postalCode = (containsPlacemark.postalCode != nil) ? containsPlacemark.postalCode : ""
            let administrativeArea = (containsPlacemark.administrativeArea != nil) ? containsPlacemark.administrativeArea : ""
            let country = (containsPlacemark.country != nil) ? containsPlacemark.country : ""

            localityTxtField.text = locality
            postalCodeTxtField.text = postalCode
            aAreaTxtField.text = administrativeArea
            countryTxtField.text = country
        }

    }


    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
          print("Error while updating location " + error.localizedDescription)
    }
}
Fideicommissary answered 27/10, 2017 at 12:23 Comment(0)
T
3

In current thread a solution was proposed without delegate but in Xcode 9.1 testing in simulator it did not work, location was nil. This code worked:

 import UIKit
 import MapKit

class ViewController: UIViewController, CLLocationManagerDelegate {

var locationManager: CLLocationManager!

override func viewDidLoad() {
    super.viewDidLoad()

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

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

    let location = locations.last! as CLLocation

    /* you can use these values*/
    let lat = location.coordinate.latitude
    let long = location.coordinate.longitude
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}
Tenno answered 31/12, 2017 at 8:17 Comment(0)
K
1

I am junior but I solved it in this way: I have created extension of my class inherited CLLocationManagerDelegate and following steps:

1.Import CoreLocation to your ViewController

import CoreLocation

2.Then initialize location manager and location variables inside your ViewController.

var locManager = CLLocationManager()
var currentUserLocation: CLLocation!
  1. Inside viewDidLoad() request location init delegate and requestUsageDescription

     locManager.requestWhenInUseAuthorization()
     locManager.delegate = self
     locManager.requestLocation()
    
  2. Then I have just created extension for my viewController inheriting CLLocationManagerDelegate

     extension theNameOfYourViewController: CLLocationManagerDelegate{
    
     func locationManager(_ manager: CLLocationManager, didFailWithError error: Swift.Error) {
     print(error)
     }
    
     func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
     // .requestLocation will only pass one location to the locations array
     // hence we can access it by taking the first element of the array
     if let location = locations.first {
     print(location.coordinate.latitude)
     print(location.coordinate.longitude)
    
       }
      }
     }
    

Just remember to change the names according your needs also whenever you need location just use the function request location

    locManager.requestLocation()
Krysta answered 6/9, 2021 at 19:43 Comment(0)
K
0

I agree with Kevin above, but if you're looking for less code for something simpler the following will suffice: Make sure to use the CLLocationManagerDelegate

Swift 4:

In viewDidLoad you can add the following

 locationManager.requestWhenInUseAuthorization()


if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse) || (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways) {

            currentLocation = locationManager.location
            print(currentLocation.coordinate.latitude)
            print(currentLocation.coordinate.longitude)

        }

    }

And for the first request respond once the user gives or denies permission:

 func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

            if status == .authorizedWhenInUse {

                locationManager.requestLocation()
                currentLocation = locationManager.location
                print(currentLocation.coordinate.latitude)
                print(currentLocation.coordinate.longitude)
                //Process location information and update.

    }
Kathrinekathryn answered 20/6, 2018 at 2:57 Comment(0)
R
0

Make sure to add the following keys to Info.plist:

Privacy - Location When In Use Usage Description Privacy - Location Always and When In Use Usage Description

Create User class:

import Foundation
import CoreLocation
import MapKit

class User: NSObject, ObservableObject {
    
    @Published var position =  CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
    
    let manager = CLLocationManager()

    override init() {
        super.init()
        manager.delegate = self
        manager.requestWhenInUseAuthorization()
        manager.requestLocation()
    }
    
}

extension User: CLLocationManagerDelegate {
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        print("Location services authorization request")
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("User location updated")
        print("Updated position: \(locations.first?.coordinate.latitude ?? 00)")
        
        if let location = locations.first {
            self.position = location.coordinate
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("Failed to find user's location: \(error.localizedDescription)")
    }

    
}
Redon answered 8/3, 2021 at 18:1 Comment(0)
U
0

Update

Swift 5+
Xcode 13+

Add these permission in info plist

<key>NSLocationWhenInUseUsageDescription</key>
    <string>This app needs your location to show nearby services</string>

    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>This app needs your location to show nearby services</string>

    <key>NSLocationAlwaysUsageDescription</key>
    <string>This app needs your location to show nearby services</string>

enter image description here

Import this in your view controller

import CoreLocation

in viewDidLoad()

override func viewDidLoad() {
        locationManager.requestWhenInUseAuthorization()
        locationManager.requestLocation()
}

Create extension like this

extension RegisterViewController : CLLocationManagerDelegate {

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
         print("error:: \(error.localizedDescription)")
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse {
            locationManager.requestLocation()
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let locationSafe = locations.last {
            locationManager.stopUpdatingLocation()
            let latitude = locationSafe.coordinate.latitude
            let longitude = locationSafe.coordinate.longitude
            self.currentLatitude = latitude
            self.currentLongitude = longitude
            print(" Lat \(latitude) ,  Longitude \(longitude)")
            
        }
        if locations.first != nil {
            print("location:: \(locations[0])")
        }

    }

}

Run and check this

enter image description here

Uzzial answered 16/12, 2021 at 18:39 Comment(1)
Dude nice tute BUT you forgot to set the delegateInglenook
I
0

2024 facts:

(*) it seems you need ALL THREE permissions, no matter what

<key>NSLocationWhenInUseUsageDescription</key>
<string>For mapping</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>For mapping</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>For mapping</string>

(*) must set the delegate or you will get a mystery crash, but no warning in Xcode

import CoreLocation

  let locationManager = CLLocationManager()

    ... locationManager.delegate = self

(*) once the view appears,

   locationManager.requestAlwaysAuthorization()
   locationManager.requestLocation()

(*) no doco, but you must include all three callbacks, or mystery crash.

To save you typing:

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    print("loc error \(error.localizedDescription)")
}

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    switch status {
    case .authorizedAlways:
        print("AUTH ALL")
        locationManager.requestLocation()
    case .authorizedWhenInUse:
        print("AUTH when")
        locationManager.requestLocation()
    case .denied:
        print("AUTH denied")
    case .restricted:
        print("AUTH restricted")
    case .notDetermined:
        print("AUTH not det")
    @unknown default:
        print("AUTH update")
    }
}

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

(*) recall, completely delete the app from device to again see the chain of permissions flow

(*) recall, it does in fact work on modern Xcode simulators (actual location may be meaningless)

Inglenook answered 15/2 at 17:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.