Wednesday, December 8, 2010

Getting Your Location in an iPhone Application


One of the great features in the iPhone is the ability to get your location, which is available on all of the versions with the 1st edition relying on cell tower triangulation, the rest using built in GPS. As a developer, I can think of endless possibilities for using this information, but the first step is getting a hold of the information. This tutorial is going to cover how to get location data using the iPhone SDK.
The goal for this tutorial is to build the super simple application, Where Am I? This application does one thing, it will tell you your current location and update itself when you move. There is much more you can do with this API, this example just shows the basics. You can see the interface with the location information below.
Ok, let's get down to it. The interface contains five UILabel controls. Pretty easy to put together and the important ones are for outputting the latitude and longitude. Just drop the labels down. We also need to update our view controller to have a couple IBOutlet variables for our labels. With the variables added go ahead and hook the labels to the IBOutlet in Interface Builder, if you need help with this check out our intro to Interface Builder. The updated view controller header file is below.
#import <UIKit/UIKit.h>

@interface WhereAmIViewController : UIViewController {
  IBOutlet UILabel *latLabel;
  IBOutlet UILabel *longLabel;
}

@end
That is all the interface building we need to do. At this point you need to add the Core Location framework, you can do this by right clicking on the "Frameworks" group and going to Add > Existing Frameworks... This will bring up a browse window, CoreLocation.framework should be an option on the right hand side. This is the framework used to get a hold of location data.
The Core Location framework has only a few classes in it, the most important being CLLocationManager. TheCLLocationManager class handles sending out updates to a delegate anytime the location is changed. Since it uses the delegate pattern we need to say that our controller implements the CLLocationManagerDelegate protocol - this is done in the header. The only other thing we need to add to the header is an instance variable for the location manager. Our completed header file is below.
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

@interface WhereAmIViewController : UIViewController 
  <CLLocationManagerDelegate>{
  CLLocationManager *locationManager;
  IBOutlet UILabel *latLabel;
  IBOutlet UILabel *longLabel;
}

@end
The rest of our code is going to be added to our controller implementation file. First, we have to setup the location manager. This includes allocating a new one and initializing some properties on it. We then have to tell it to start updating the delegate. This is all done inside the viewDidLoad method.
- (void)viewDidLoad {
  [super viewDidLoad];
  locationManager = [[CLLocationManager alloc] init];
  locationManager.delegate = self;
  locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
  locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
  [locationManager startUpdatingLocation];
}
You can see above we set the delegate to our self. The second and third properties define how often the manager will update the location. distanceFilter defines how far the location has to move before it will send out an update,kCLDistanceFilterNone means it will always send an update no matter how far the location moves. The last property, desiredAccuracy, decides how accurate the location on the phone needs to be in order to be included as an update, I have it set to kCLLocationAccuracyHundredMeters (100 m).
If you look at the delegate protocol you will see there are several methods that can be implemented, but really the only one that we need to implement is:
- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation
The delegate method above will be called when there is a new location available. You will notice we get both the old and new locations coming in as CLLocation objects. A CLLocation object has the coordinates, accuracy, altitude, and a timestamp. We are only interested in the coordinates - which has the latitude and longitude. The complete code for our delegate method is below, I will go into more details afterwords.
- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation
{
  int degrees = newLocation.coordinate.latitude;
  double decimal = fabs(newLocation.coordinate.latitude - degrees);
  int minutes = decimal * 60;
  double seconds = decimal * 3600 - minutes * 60;
  NSString *lat = [NSString stringWithFormat:@"%d° %d' %1.4f\""
                   degrees, minutes, seconds];
  latLabel.text = lat;
  degrees = newLocation.coordinate.longitude;
  decimal = fabs(newLocation.coordinate.longitude - degrees);
  minutes = decimal * 60;
  seconds = decimal * 3600 - minutes * 60;
  NSString *longt = [NSString stringWithFormat:@"%d° %d' %1.4f\""
                     degrees, minutes, seconds];
  longLabel.text = longt;
}
Basically, we take the location and turn the degrees into degrees, minutes, and seconds then display the value in the correct label. We're using fabs instead of abs to get the absolute value since we need the decimal value. The math is pretty simple. Each degree is 60 minutes or 3600 seconds. We start by chopping off the degrees then calculating the whole number of minutes and finish by calculating seconds. Using simple NSString stringWithFormat we create a nice pretty output location string. The final thing we do is set the text of the correct label.
With that, everything seems to be done. We have built the simplest location application you can, but it teaches you how use the core location framework. The framework also includes heading (direction pointed) information but we didn't take a look at this. It works in pretty much the exact same manner. As always, the source code is available below for download. If you have any questions feel free to leave comment.

No comments:

Post a Comment

Followers