Location

holesToday, a quick guide through basic location services on the iPhone 3G (i.e. I’m not handling heading information here.) I run through a quick overview of the steps involved in building a basic location-aware app, and provide a complete Xcode project for your perusal.

The Goal

I want to build a simple GPS console, that will provide:

  • Latitude/Longitude (w/ accuracy)
  • Altitude (w/ accuracy)
  • Course and Speed

Fortunately, this is really easy.

Getting Started

Open Xcode, and start a New Project. Choose to create a “View-Based Application” when asked. You’ll be able to use the application delegate and main window NIB files exactly as they were created for you.

Frameworks

The biggest gotcha is failing to add the Core Location framework to your project. Right-click your target, then select “Add”->”Existing Frameworks…”. Click the plus icon underneath the Linked Libraries pane, and add the CoreLocation framework.

Members and Outlets

Open the Xcode-created View Controller .h file, and alter its definition to look like this:

@interface LocXViewController : UIViewController <CLLocationManagerDelegate>
{
	CLLocationManager*	manager;
	NSDateFormatter*	formatter;
	
	UILabel*		latitude;
	UILabel*		longitude;
	UILabel*		h_accuracy;

	UILabel*		altitude;
	UILabel*		v_accuracy;

	UILabel*		course;
	UILabel*		speed;

	UILabel*		updated;
	UILabel*		updated_suffix;
}

@property (nonatomic, retain) IBOutlet UILabel* latitude;
@property (nonatomic, retain) IBOutlet UILabel* longitude;
@property (nonatomic, retain) IBOutlet UILabel* h_accuracy;
@property (nonatomic, retain) IBOutlet UILabel* altitude;
@property (nonatomic, retain) IBOutlet UILabel* v_accuracy;
@property (nonatomic, retain) IBOutlet UILabel* course;
@property (nonatomic, retain) IBOutlet UILabel* speed;
@property (nonatomic, retain) IBOutlet UILabel* updated;
@property (nonatomic, retain) IBOutlet UILabel* updated_suffix;

@end

(Remember to #import CoreLocation/CoreLocation.h in this header file.)

Next, open the View Controller .m file, add @synthesize statements, and recode dealloc thusly:

@implementation LocXViewController

@synthesize latitude;
@synthesize longitude;
@synthesize h_accuracy;
@synthesize altitude;
@synthesize v_accuracy;
@synthesize course;
@synthesize speed;
@synthesize updated;
@synthesize updated_suffix;

// ... etc ...

- (void)dealloc
{
	[manager release];
	[formatter release];

	[latitude release];
	[longitude release];
	[h_accuracy release];
	[altitude release];
	[v_accuracy release];
	[course release];
	[speed release];
	[updated release];
	[updated_suffix release];

	[super dealloc];
}

// ... etc ...

@end

Finally, save your work and open up the View Controller NIB in Interface Builder. Design an output screen that appeals to you. Connect up the outlets you just created to the labels that will display the various data elements. (In the project packaged with this post, I provide a sample NIB file.)

Payoff

Only two bits of code need to be added to make this application “go”. First, override the designated initializer:

- (id)initWithCoder:(NSCoder*)coder
{
    if (self = [super initWithCoder:coder])
    {
	formatter = [[NSDateFormatter alloc] init];
	formatter.AMSymbol = @"am";
	formatter.PMSymbol = @"pm";
	formatter.dateFormat = @"h:mm:ssa";
		
	manager = [[CLLocationManager alloc] init];
	manager.delegate = self;
	
	[manager startUpdatingLocation];
    }
    return self;
}

Last, implement one CLLocationManagerDelegate method:

- (void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation
{
	if (newLocation.horizontalAccuracy < 0)
	{
		latitude.text	= @"N/A ";
		longitude.text	= @"N/A ";
		h_accuracy.text	= @"N/A ";
	}
	else
	{
		latitude.text	= [NSString stringWithFormat:@"%.6f",newLocation.coordinate.latitude];
		longitude.text	= [NSString stringWithFormat:@"%.6f",newLocation.coordinate.longitude];
		h_accuracy.text	= [NSString stringWithFormat:@"%d",(int) newLocation.horizontalAccuracy];
	}
	
	if (newLocation.verticalAccuracy < 0)
	{
		altitude.text	= @"N/A ";
		v_accuracy.text	= @"N/A ";
	}
	else
	{
		altitude.text	= [NSString stringWithFormat:@"%d",(int) newLocation.altitude];
		v_accuracy.text	= [NSString stringWithFormat:@"%d",(int) newLocation.verticalAccuracy];
	}
	
	course.text			= (newLocation.course<0)?@"N/A ":[NSString stringWithFormat:@"%d",(int) newLocation.course];
	speed.text			= (newLocation.speed<0)?@"N/A ":[NSString stringWithFormat:@"%d",(int) newLocation.speed];
	
	NSString* ts		= [formatter stringFromDate:newLocation.timestamp];
	updated.text		= [ts substringToIndex:[ts length]-2];
	updated_suffix.text	= [ts substringFromIndex:[ts length]-2];
}

Sample Code

You can download an Xcode project implementing the sort of application we’ve just built here. (Note that this project is slightly more elaborate, and adds an on/off switch for location updates.)

Share and Enjoy:
  • Twitter
  • Facebook
  • Digg
  • Reddit
  • HackerNews
  • del.icio.us
  • Google Bookmarks
  • Slashdot
This entry was posted in iPhone. Bookmark the permalink.

One Response to Location

  1. tommy says:

    Hi, Michael.Thank you so much for sharing this. For you, maybe it’s just an easy task. For me, a novice level ios programmer, it’s a wonderful article to read.Thank you again.
    Tommy