Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / iPhone

iOS 4 in Action - Using Location Monitoring Service

4.50/5 (2 votes)
20 May 2011CPOL5 min read 20.9K  
A Chapter excerpt from iOS 4 in Action
image002.jpgiOS 4 in Action
Developing iPhone & iPad Apps

By Jocelyn Harrington, Brandon Trebitowski, Christopher Allen, and Shannon Appelcline

An application can receive location updates to support a location-related task or navigation in the background, such as significant location change service and turn-by-turn directions. In this article, based on chapter 22 of iOS 4 in Action, the authors build a demo application that tracks location updates in the background.

To save 35% on your next purchase use Promotional Code jharrington2235 when you check out at www.manning.com.

You may also be interested in…

When an application needs to continue running in the background, these multitasking features are available on iOS 4:

  • Audio—The application can continue running and play audio to the user while in the background. The user can use the multitasking UI or the lock screen UI to remote control the audio play, pause, fast-forward, and so on.
  • Location—The application can receive location updates to support a location-related task or navigation in the background, such as significant location change service and turn-by-turn directions.
  • VoIP—Allows the application to receive voice calls through the Internet while other applications are in the foreground. 

In this article, we will build a demo application that tracks the location updates in the background.

Updating the UI when the Application Relaunches

The first step is to create an application to display the collected location data. First, open Xcode and create a project using a navigation-based application template in the iOS application projects. Name it Locations. In this application, we will use a table view to display all the new location updates from the location service running in the background.

The application’s view controller needs to update the user interface when the location is restarted from the background state.

Inside the RootViewConroller.h file, define an array locationData and use it as table view’s data source, as shown in the following listing. Then, in the RootViewController.m file, display the location data on the table view. Keep in mind that the table view needs to reload the data when the application is restarted from the background.

Listing 1 RootViewController’s header file and implementation file

#import <UIKit/UIKit.h>
@interface RootViewController : UITableViewController {
     NSArray *locationData;
}
@property (nonatomic, retain) NSArray *locationData;
@end                                   
 
#import "RootViewController.h"               
@implementation RootViewController
@synthesize locationData;
 
- (void)updateUI {
     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
     self.locationData = [defaults objectForKey:@"kLocationData"];
     [self.tableView reloadData];
}
 
- (void)viewDidLoad {
    [super viewDidLoad];
     self.title = @"Locations";
     [self updateUI];
     NSNotificationCenter *notifcenter = [NSNotificationCenter defaultCenter];
     [notifcenter addObserver:self selector:@selector(updateUI) name:UIApplicationWillEnterForegroundNotification object:nil];
}
 
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
 
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [locationData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
     cell.textLabel.text = [locationData objectAtIndex:indexPath.row];
    return cell;
}
- (void)dealloc {
     [locationData release];
    [super dealloc];
}
@end

When the table view controller gets loaded, the locationData array will fetch the data stored with NSUserDefaults, then update the table view based on the locationData array. The notification center will observe the event when the application resumes from the background state and reload the table view’s data.

Now we have the table view ready to display the location data. Next, let’s look at how to get the location updates from the Core Location framework with the significant location update service. 

Enabling Significant Location Change Service

In this part, we will add the significant location change service to our application locations. First, we add the Core Location framework to the project and include the core location header in the app delegate file. Then, let’s add the Core Location Manager to the app delegate as an instance variable: CLLocationManager *locationManager. Now, we will add changes from the following listing to the app delegate implementation file to enable the location monitoring service when the app launches.

Listing 2 Implementing Location Updates in the Background

#import "LocationsAppDelegate.h"
#import "RootViewController.h"
 
@implementation LocationsAppDelegate
@synthesize window;
@synthesize navigationController;
 
-(void)initLocationManager {                         #1
     if (locationManager == nil) {
          locationManager = [[CLLocationManager alloc] init];
          locationManager.delegate = self;
          [locationManager startMonitoringSignificantLocationChanges];
     }
}
- (void)saveCurrentData:(NSString *)newData {               #2
     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
     NSMutableArray *savedData = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"kLocationData"]];
     [savedData addObject:newData];
     [defaults setObject:savedData forKey:@"kLocationData"];
     [savedData release];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions      
{ 
  if (![CLLocationManager significantLocationChangeMonitoringAvailable]) #3 
{UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Sorry" message:@"Your device won't support the significant location change." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
          [alert show];
          [alert release];
          return YES;                                   #3
     }                                             #3
     [self initLocationManager];
    [self.window addSubview:navigationController.view];
    [self.window makeKeyAndVisible];
    return YES;
}
 
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {                                        #4
     NSString *locationData = [NSString stringWithFormat:@"%.6f, %.6f",newLocation.coordinate.latitude, newLocation.coordinate.longitude];
     [self saveCurrentData:locationData];
}                                                  #4
 
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {                         #5
     NSString *errorData = [NSString stringWithFormat:@"%@",[error localizedDescription]];
     NSLog(@"%@", errorData);                              #5
}
- (void)dealloc {
     [[NSNotificationCenter defaultCenter] removeObserver:self];
[locationManager release];
    [navigationControllerrelease];
    [window release];
    [super dealloc];
}

@end

#1 Starts location service
#2 Stores data
#3 Tests if location service is available
#4 Updates location data
#5 Error handling

Inside the application delegate, we use the Core Location Manager to monitor the significant location change. When the application first launches, we call method initLocationManager (#1) to initialize the location manager and start the significant location update service. In order to make sure the location service is actually available on this device, we use method significantLocationChangeMonitoringAvailable (#3) to test the availability and, if not possible, to use the location update service on this device, we give user an alert.

Once the new location is available, the location manager delegate method is called (#4). We need to store the new location data using NSDefaults in method saveCurrentData (#2). That’s how the table view can get all the new location updates from the application delegate. 

In case an error occurs during location updating, the location manager calls the delegate method (#5). We can read out the error message inside the Console Window under Xcode.

You need to test this application on your iPhone or iPad with 3G since the simulator won’t support the location change service. Build and run this application on the device. Quit the application to let the location service run in the background.

The locations application will continue receiving updates in the background and, once it’s relaunched, you can track all the places you’ve been to. Notice that, even if the application is suspended in the background or the application is not running at all, the location service is running. You can tell by the indicator on the status bar of your iPhone or iPad 3G, as shown in figure 1.

image003.gif

Figure 1 Significant location updates application running in the background

You can combine this significant location updates service and notify user with local notifications. The region-based location monitoring service works exactly like the significant location updates service. You can define which region to monitor; when the user enters that specific region, the application will receive the location update through core location delegate methods. The system will wake up the application even if the application is not running or is suspended.

Summary

In this article, we dug into the multitasking topic and built the location tracking application with background significant location updates.

Here are some other Manning titles you might be interested in:

image004.jpg

Objective-C for the iPhone
Christopher K. Fairbairn and Collin Ruffenach

image005.jpg

iPhone in Practice
Bear P. Cahill

image006.jpg

Unlocking Android, Second Edition
W. Frank Ableson and Robi Sen

Last updated: May 18, 2011

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)