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
Collapse
#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
Collapse
#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.
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.