iOS Reference Library Apple Developer
Search

Getting the User’s Location

Applications use location data for a wide variety of purposes, ranging from social networking to turn-by-turn navigation services. They get location data by using the classes of the Core Location framework. This framework provides several services that you can use to get and monitor the device’s current location:

To use the features of the Core Location framework, you must link your application to CoreLocation.framework in your Xcode project. To access the classes and headers of the framework, include an #import <CoreLocation/CoreLocation.h> statement at the top of any relevant source files.

For general information about the classes of the Core Location framework, see Core Location Framework Reference.

Requiring the Presence of Location Services in Order to Run

If your application relies on location services to function properly, you should include the UIRequiredDeviceCapabilities key in the application’s Info.plist file. You use this key to specify the location services that must be present in order for your application to run. The App Store uses the information in this key from preventing users from downloading applications to devices that do not contain the listed features.

The value for the UIRequiredDeviceCapabilities is an array of strings indicating the features that your application requires. There are two strings relevant to location services:

Important: If your application uses location services but is able to operate successfully without them, do not include the corresponding strings in the UIRequiredDeviceCapabilities key.

For more information about the UIRequiredDeviceCapabilities key, see Information Property List Key Reference.

Getting the User’s Current Location

The Core Location framework lets you locate the current position of the device and use that information in your application. The framework uses information obtained from the built-in cellular, Wi-Fi, or GPS hardware to triangulate a location fix for the device. It reports that location to your code and, depending on how you configure the service, also provides periodic updates as it receives new or improved data.

There are two different services you can use to get the user’s current location:

Gathering location data is a power-intensive operation. It involves powering up the onboard radios and querying the available cell towers, Wi-Fi hotspots, or GPS satellites, which can take several seconds. Leaving the standard location service running for extended periods can drain the device’s battery. (The significant-change location service drastically reduces battery drain by monitoring only cell tower changes, but the service works only on devices with cellular radios.) For most applications, it is usually sufficient to establish an initial position fix and then acquire updates only periodically after that. If you are sure you need regular position updates, you should use the significant-change location service where you can; otherwise, you should configure the parameters of the standard location service in a way that minimizes its impact on battery life.

Determining Whether Location Services Are Available

Every iOS-based device is capable of supporting location services in some form but there are still situations where location services may not be available:

For these reasons, it is recommended that you always call the locationServicesEnabled class method of CLLocationManager before attempting to start either the standard or significant-change location services. (In iOS 3.x and earlier, check the value of the locationServicesEnabled property instead.) If this class method returns YES, you can start location services as planned. If it returns NO and you attempt to start location services anyway, the system prompts the user to confirm whether location services should be reenabled. Given that location services are very likely to be disabled on purpose, the user might not welcome this prompt.

Starting the Standard Location Service

The standard location service is the most common way to get the user’s current location because it is available on all devices and in all versions of iOS. Before using this service, you configure it by specifying the desired accuracy of the location data and the distance that must be traveled before reporting a new location. When you start the service, it uses the specified parameters to determine which radios to enable and then proceeds to report location events to your application.

To use the standard location service, create an instance of the CLLocationManager class and configure its desiredAccuracy and distanceFilter properties. To begin receiving location notifications, assign a delegate to the object and call the startUpdatingLocation method. As location data becomes available, the location manager notifies its assigned delegate object. If a location update has already been delivered, you can also get the most recent location data directly from the CLLocationManager object without waiting for a new event to be delivered.

Listing 1-1 shows a sample method that configures a location manager for use. This method is part of a class that caches its location manager object in a member variable for later use. (The class also conforms to the CLLocationManagerDelegate protocol and so acts as the delegate for the location manager.) Because the application does not need precise location data, it configures the location service to report the general area of the user and notify it only when the user moves a significant distance, which in this case is half a kilometer.

Listing 1-1  Starting the standard location service

- (void)startStandardUpdates
{
    // Create the location manager if this object does not
    // already have one.
    if (nil == locationManager)
        locationManager = [[CLLocationManager alloc] init];
 
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
 
    // Set a movement threshold for new events.
    locationManager.distanceFilter = 500;
 
    [locationManager startUpdatingLocation];
}

The code for receiving location updates from this service is shown in “Receiving Location Data from a Service.”

Starting the Significant-Change Location Service

In iOS 4.0 and later, you can use the significant-change location service to receive location events. This service offers a significant power savings and provides accuracy that is good enough for most applications. It uses the device’s cellular radio to determine the user’s location and report changes in that location, allowing the system to manage power usage much more aggressively than it could otherwise. This service is also capable of waking up an application that is currently suspended or not running in order to deliver new location data.

To use the significant-change location service, create an instance of the CLLocationManager class, assign a delegate to it, and call the startMonitoringSignificantLocationChanges method as shown in Listing 1-2. As location data becomes available, the location manager notifies its assigned delegate object. If a location update has already been delivered, you can also get the most recent location data directly from the CLLocationManager object without waiting for a new event to be delivered.

Listing 1-2  Starting the significant-change location service

- (void)startSignificantChangeUpdates
{
    // Create the location manager if this object does not
    // already have one.
    if (nil == locationManager)
        locationManager = [[CLLocationManager alloc] init];
 
    locationManager.delegate = self;
    [locationManager startMonitoringSignificantLocationChanges];
}

As with the standard location service, location data is delivered to the delegate object as described in “Receiving Location Data from a Service.”

If you leave this service running and your application is subsequently suspended or terminated, the service automatically wakes up your application when new location data arrives. At wake-up time, your application is put into the background and given a small amount of time to process the location data. Because your application is in the background, it should do minimal work and avoid any tasks (such as querying the network) that might prevent it from returning before the allocated time expires. If it does not, your application may be terminated.

Receiving Location Data from a Service

Whether you use the standard location service or the significant-change location service to get location events, the way you receive those events is the same. Whenever a new event is available, the location manager reports it to the locationManager:didUpdateToLocation:fromLocation: method of its delegate. If there is an error retrieving an event, the location manager calls the locationManager:didFailWithError: method of its delegate instead.

Listing 1-3 shows the delegate method for receiving location events. Because the location manager object sometimes returns cached events, it is recommended that you check the timestamp of any location events you receive. (It can take several seconds to obtain a rough location fix, so the old data simply serves as a way to reflect the last known location.) In this example, the method throws away any events that are more than fifteen seconds old under the assumption that fairly recent events are likely to be good enough. If you were implementing a navigation application, you might want to lower the threshold.

Listing 1-3  Processing an incoming location event

// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
    fromLocation:(CLLocation *)oldLocation
{
    // If it's a relatively recent event, turn off updates to save power
    NSDate* eventDate = newLocation.timestamp;
    NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
    if (abs(howRecent) < 15.0)
    {
        NSLog(@"latitude %+.6f, longitude %+.6f\n",
                newLocation.coordinate.latitude,
                newLocation.coordinate.longitude);
    }
    // else skip the event and process the next one.
}

In addition to a location object’s timestamp, you can also use the accuracy reported by that object as a means of determining whether you want to accept an event. As it receives more accurate data, the location service may return additional events, with the accuracy values reflecting the improvements accordingly. Throwing away less accurate events means your application wastes less time on events that cannot be used effectively anyway.

Monitoring Shape-Based Regions

In iOS 4.0 and later, applications can use region monitoring to be notified when the user crosses geographic boundaries. You can use this capability to generate alerts when the user gets close to a specific location. For example, upon approaching a specific dry cleaners, an application could notify the user to pick up any clothes that had been dropped off and are now ready.

Regions associated with your application are tracked at all times, including when your application is not running. If a region boundary is crossed while an application is not running, that application is relaunched into the background to handle the event. Similarly, if the application is suspended when the event occurs, it is woken up and given a short amount of time to handle the event.

Determining the Availability of Region Monitoring

Before attempting to monitor any regions, your application should check to see if region monitoring is supported on the current device. There are several reasons why region monitoring might not be available:

For these reasons, it is recommended that you always call the regionMonitoringAvailable and regionMonitoringEnabled class methods of CLLocationManager before attempting to monitor regions. The regionMonitoringAvailable method lets you know whether the underlying hardware supports region monitoring. If it returns NO, there is no chance that your application will ever be able to use region monitoring on the device. If region monitoring is available, the regionMonitoringEnabled method reports whether the feature is currently enabled. If region monitoring is available but not enabled when you attempt to monitor a region, the system prompts the user to confirm whether region monitoring should be reenabled. Given that the feature is likely to be disabled on purpose, the user might not welcome this prompt.

Defining a Region to Be Monitored

To begin monitoring a region, you must define the region and register it with the system. Regions are defined using the CLRegion class, which currently supports the creation of circular regions. Each region you create must include both the data that defines the desired geographic area and a unique identifier string. (The identifier string is required and is the only guaranteed way for your application to identify regions later.) To register a region, you call the startMonitoringForRegion:desiredAccuracy: method of your CLLocationManager object.

Listing 1-4 shows a sample method that creates a new region based on a circular Map Kit overlay. The overlay’s center point and radius form the boundary for the region, although if the radius is too large to be monitored, it is reduced automatically. After registering the region, the region object itself can be released. Core Location stores the data associated with a region but does not typically store the region object itself.

Listing 1-4  Creating and registering a region based on a Map Kit overlay

- (BOOL)registerRegionWithCircularOverlay:(MyCircle*)overlay andIdentifier:(NSString*)identifier
{
   // Do not create regions if support is unavailable or disabled.
   if ( ![CLLocationManager regionMonitoringAvailable] ||
        ![CLLocationManager regionMonitoringEnabled] )
      return NO;
 
   // If the radius is too large, registration fails automatically,
   // so clamp the radius to the max value.
   CLLocationDegrees radius = overlay.radius;
   if (radius > self.locManager.maximumRegionMonitoringDistance)
      radius = self.locManager.maximumRegionMonitoringDistance;
 
   // Create the region and start monitoring it.
   CLRegion* region = [[CLRegion alloc] initCircularRegionWithCenter:overlay.coordinate
                        radius:radius identifier:identifier];
   [self.locManager startMonitoringForRegion:region
                    desiredAccuracy:kCLLocationAccuracyHundredMeters];
 
   [region release];
   return YES;
}

Monitoring of a region begins immediately after registration. However, do not expect to receive an event right away. Only boundary crossings can generate an event. Thus, if at registration time the user’s location is already inside the region, the location manager does not generate an event. Instead, you must wait for the user to cross the region boundary before an event is generated and sent to the delegate.

You should always be judicious when specifying the set of regions to monitor. Regions are a shared system resource and the total number of regions available systemwide is limited. For this reason, Core Location limits the number of regions that may be simultaneously monitored by a single application. To work around these limits, you should consider registering only those regions in the user’s immediate vicinity. As the user’s location changes, you can remove regions that are now farther way and add regions coming up on the user’s path. If you attempt to register a region and space is unavailable, the location manager calls the locationManager:monitoringDidFailForRegion:withError: method of its delegate with the kCLErrorRegionMonitoringFailure error code.

Handling Boundary-Crossing Events for a Region

Every time the user’s current location crosses a boundary region, the system generates an appropriate region event for your application. If your application is already running, these events go directly to the delegates of any current location manager objects. If your application is not running, the system launches it in the background so that it can respond. Applications can implement the following methods to handle boundary crossings:

The system does not report boundary crossings until the boundary plus a designated cushion distance is exceeded. You specify the desired cushion distance for a region when you register it using the startMonitoringForRegion:desiredAccuracy: method. This cushion value prevents the system from generating numerous entered and exited events in quick succession while the user is traveling close the edge of the boundary.

When a region boundary is crossed, the most likely response is to alert the user of the proximity to the target item. If your application is running in the background, you can use local notifications to alert the user; otherwise, you can simply post an alert.

Getting Location Events in the Background

If your application needs location updates delivered whether the application is in the foreground or background, there are multiple options for doing so. The preferred option is to use the significant location change service to wake your application at appropriate times to handle new events. However, if your application needs to use the standard location service, you can declare your application as needing background location services.

An application should request background location services only if the absence of those services would impair its ability to operate. In addition, any application that requests background location services should use those services to provide a tangible benefit to the user. For example, a turn-by-turn navigation application would be a likely candidate for background location services because of its need to track the user’s position and report when it is time to make the next turn.

The process for configuring a background location application is described in “Executing Code in the Background” in iOS Application Programming Guide.

Tips for Conserving Battery Power

Receiving and transmitting data using the radios of an iOS-based device require more power than any other operation on the device. Because Core Location relies on these radios to determine the user’s location, you should use location services judiciously in your applications. Most applications do not need location services to be running all the time, and so turning off those services is the simplest way to save power.




Last updated: 2010-05-20

Did this document help you? Yes It's good, but... Not helpful...