Updated about 5 hours ago | GitHub

Location Quickstart

Location

Step 1: Import the Location Framework

Modern Xcode auto-links Core Location when the module is referenced, so no manual Build Phases entry is required — just add import CoreLocation to the top of any file that uses CLLocationManager and related types.

Step 2: Identifying the desired location permission

So the first thing you need to do is to add the appropriate keys to your Info.plist file:

  • NSLocationWhenInUseUsageDescription — required if you call requestWhenInUseAuthorization().
  • NSLocationAlwaysAndWhenInUseUsageDescription — required if you call requestAlwaysAuthorization() on iOS 11+ (the older NSLocationAlwaysUsageDescription is deprecated).

Note: requesting “Always” authorization on iOS 11 and later requires both keys to be present in Info.plist. If NSLocationWhenInUseUsageDescription is missing, requestAlwaysAuthorization() will silently fail and no permission prompt will be shown. For the when-in-use-only flow shown below, NSLocationWhenInUseUsageDescription alone is sufficient; add NSLocationAlwaysAndWhenInUseUsageDescription as well if your app will ever escalate to always-on background access.

Step 3: Create the location manager

In the app delegate,

import CoreLocation

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    var locationManager: CLLocationManager! = CLLocationManager()

Step 4: Request permission

Apple’s guidance is to request the least level of authorization your feature needs. If your app only reads the user’s location while the UI is on screen, call requestWhenInUseAuthorization(); you can later escalate to requestAlwaysAuthorization() in response to a user action that clearly needs background updates (for example, enabling a “notify me when I arrive” feature). See Requesting authorization to use location services for the full authorization model.

locationManager.requestWhenInUseAuthorization()
// Escalate to always-on background access only when a feature explicitly needs it:
// locationManager.requestAlwaysAuthorization()

Step 5: Start Updating Location

Wait to call startUpdatingLocation() until the user has authorized location access. Location updates will not begin flowing until authorization is granted, so calling it earlier just leaves the manager idle; you can still observe denial or a status change through the authorization-change delegate callback (locationManagerDidChangeAuthorization(_:) on iOS 14+, or locationManager(_:didChangeAuthorization:) on older deployment targets) whether or not startUpdatingLocation() was called first. The clean pattern is to start updates from the .authorizedAlways / .authorizedWhenInUse branch of that delegate method in Step 6:

// Called from CLLocationManagerDelegate once authorization is granted:
locationManager.startUpdatingLocation()

Step 6: Implement Location Delegate

Set locationManager.delegate = self and adopt CLLocationManagerDelegate. Since iOS 14, the delegate method that fires when the authorization status changes is locationManagerDidChangeAuthorization(_:); it replaces the older locationManager(_:didChangeAuthorization:). Read the current status from the authorizationStatus instance property on the manager (also iOS 14+) rather than the deprecated CLLocationManager.authorizationStatus() type method.

@available(iOS 14.0, *)
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
    switch manager.authorizationStatus {
    case .authorizedAlways, .authorizedWhenInUse:
        manager.startUpdatingLocation()
    case .denied, .restricted:
        // Surface an in-app explanation and, if useful, point the user at Settings.
        break
    case .notDetermined:
        // Still waiting for the user's response to the permission prompt.
        break
    @unknown default:
        break
    }
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    guard let location = locations.first else { return }

    print(location)
}

On projects whose deployment target is older than iOS 14, keep implementing the pre-iOS-14 locationManager(_:didChangeAuthorization:) callback and read CLLocationManager.authorizationStatus() as the type method.