Skip to content
macOSDeep Dive Published Updated 7 min readViews unavailable

Core Location on macOS: Authorization, Update Lifecycles, and Accuracy

Use CLLocationManager on macOS with explicit authorization, fit-for-purpose accuracy, retained delegates, stale-fix handling, and measurable update policies.

Core Location provides location data to macOS applications when the service, hardware, operating-system policy, and user authorization allow it. A location request is not a promise that a fresh GPS fix exists, that updates arrive at a fixed cadence, or that the app can keep receiving them after its lifecycle changes. Production code should treat authorization and availability as runtime state, describe a useful fallback when location is missing, and ask only for the precision and duration the feature needs.

On macOS, the familiar CLLocationManager delegate API remains useful for a one-shot lookup or a bounded update session. The manager calls its delegate using the run loop of the thread on which the manager was initialized. If that thread has no active run loop, callbacks may not arrive as expected. For an AppKit feature, create and own the manager on the main thread or another thread whose run loop is intentionally serviced.

Choose a request shape

Use requestLocation() when the UI needs one current result and then should stop. Use startUpdatingLocation() only while the feature genuinely needs a continuing stream, and pair it with stopUpdatingLocation() when the owner no longer needs updates. Do not start continuous location simply to populate a one-time label. For region monitoring, heading, or beacon ranging, check service-specific availability and use the service whose behavior matches the product requirement.

desiredAccuracy and distanceFilter communicate the quality and movement threshold that matter to the app. They are not a fixed sampling interval or a contractual guarantee that the system will return that exact accuracy. Requesting higher precision than the feature needs can increase resource use and expose more sensitive detail without improving the user experience. Make the accuracy choice explicit and review it whenever the feature changes.

import CoreLocation

final class OneShotLocation: NSObject, CLLocationManagerDelegate {
    private let manager = CLLocationManager()

    override init() {
        super.init()
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
    }

    func requestCurrentLocation() {
        manager.requestLocation()
    }

    func locationManager(_ manager: CLLocationManager,
                         didUpdateLocations locations: [CLLocation]) {
        guard let newest = locations.last else { return }
        print("Received location timestamp: \(newest.timestamp)")
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        NSLog("Location request failed: %@", String(describing: error))
    }
}

The example keeps a strong manager and installs the delegate during initialization. A real app should send a validated coordinate to its model or UI instead of printing it. The class is deliberately not marked @MainActor so the snippet demonstrates the documented delegate shape; choose one actor or run-loop owner in the actual project and marshal UI changes to the main actor.

Authorization is a state machine

Do not assume that constructing a manager means access is granted. Check the current authorization status and wait for locationManagerDidChangeAuthorization(_:) after requesting access. A person can deny, restrict, or later change permission in System Settings. The UI should distinguish unavailable service from denied permission and offer an alternative workflow where the feature can still function.

For a macOS app, include the required NSLocationUsageDescription key in its information property list. Do not substitute iOS’s NSLocationWhenInUseUsageDescription or NSLocationAlwaysAndWhenInUseUsageDescription; Apple’s property-list reference directs macOS apps to the macOS-specific key. Explain the product benefit in plain language and request access in context, when the person activates a feature that needs it. Do not show a permission prompt at launch if the app has not yet explained why location is useful. If a feature can accept a city, postal code, or manual selection, keep that path available when precise location is unavailable.

macOS hardware is heterogeneous. A desktop Mac, a portable Mac, and a virtualized environment may expose different location sources and capabilities. Ask the manager about service availability immediately before using a specialized service. A network-derived result may have materially different uncertainty from a high-accuracy positioning source; communicate uncertainty in the product rather than presenting every coordinate as equally precise.

Interpret results rather than accepting the newest callback blindly

The delegate can receive an array of locations. Inspect timestamps, horizontal accuracy, and whether the result is stale for the feature. A fresh callback can still have poor accuracy, and an older location can remain the best available result during a temporary outage. Define a feature-specific acceptance window: navigation, nearby recommendations, and a place label have different requirements.

Never use coordinates as durable identity for a place or person. Location is a measurement with uncertainty, not a database key. If the app needs to remember a chosen place, store a product-level place identifier or an explicitly user-selected address. When a result is invalid, show an unknown or approximate state rather than coercing it to a plausible-looking value.

Errors are part of the request lifecycle. Handle denied authorization, location unknown, and other failures distinctly enough to provide useful feedback. A location-unknown result may justify waiting for a later update while the feature remains active; an authorization denial does not. Avoid a retry loop that creates new managers or prompts repeatedly without a user action.

Ownership, threading, and teardown

Retain the manager for the entire period in which it is expected to deliver updates. Assign the delegate immediately because authorization status can be reported after initialization. The delegate callback runs on the manager’s initialization thread’s run loop; if that is not the main thread, do not mutate AppKit controls directly. Send an immutable result to the model actor and reject a callback if its session generation has already been stopped or replaced.

When a view closes, decide whether location belongs to the view, its window, or an app-level service. Stop updates when the owning feature no longer needs them, but do not make a global service depend on a temporary view’s lifetime. Release observers and manager references together. Repeatedly starting managers for the same feature can produce duplicate callbacks and confusing authorization flow.

Background location delivery has additional operating-system and product constraints. Do not assume a standard macOS app can run indefinitely in the background because it owns a CLLocationManager. Design around the app’s actual lifecycle and documented capabilities, and test sleep, wake, logout, and process termination if the feature depends on continued monitoring.

Privacy and data minimization

Location can reveal routines, home and work locations, and sensitive visits. Collect only while the feature is active, keep the requested accuracy proportional to the user-visible purpose, and avoid logging raw coordinates. If the app stores or transmits location, explain that use and follow its retention and protection policy. Do not attach exact coordinates to analytics simply because an analytics event is already being sent.

Separate on-device UI context from data that leaves the Mac. A nearby-results feature may need a transient coordinate to filter a local catalog; it may not need to upload the exact measurement to a server. If remote lookup is necessary, send the smallest useful precision and make that network behavior part of the privacy design.

Diagnostics and acceptance criteria

Test authorization not determined, allowed, denied, changed in System Settings, services unavailable, no initial fix, stale location, poor accuracy, repeated fixes, and manager teardown. Test on a Mac with and without built-in location hardware and in the virtualization or remote environment your users actually run. Assert that the feature remains usable through its documented fallback.

Record request type, requested accuracy, callback timestamp age, reported accuracy radius, authorization status, duration, and terminal result. Keep coordinates out of ordinary logs. Measure how long one-shot requests take and how often continuous callbacks materially change the feature’s output. Use those measurements to tune accuracy and distanceFilter; do not create a synthetic polling timer around Core Location.

The dependable model is a retained manager, explicit authorization handling, a request matched to the feature, stale-result policy, and a defined stop boundary. Core Location supplies observations when available; the app remains responsible for making uncertain data understandable and safe to use.

Related:

Sources:

Comments