| iOS 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.
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:
Last updated: May 18, 2011