Apple’s done a great job of abstracting GPS, Cellular Triangulation, and Wifi Access Point location lookups into CoreLocation; making it extremely easy to determine the approximate location of your user regardless of their device and network connectivity. Additionally, Apple’s new iPhone Simulator finally supports CoreLocation as well. This significantly eases the process of testing your location code.
The first thing you’ll need to do is add the CoreLocation framework to your project. This is pretty straightforward. Command-Click on ‘Frameworks’ -> Add -> Existing Frameworks
Select ‘CoreLocation.framework’ and click ‘add’.
The class below implements the LocationManager delegate methods required to get the user’s location. You can just as easily implement the LocationManagerDelegate protocol in your AppDelegate or elsewhere in your App. Though I’ve found that having this class makes it super easy to drop in location support into new projects instead of having to cut/paste delegate methods (ugly). Anyway. Take a look:
// // LocationGetter.h // CoreLocationExample // // Created by Matt on 9/3/10. // Copyright 2009 iCodeBlog. All rights reserved. // #import <uikit/UIKit.h> #import <coreLocation/CoreLocation.h> @protocol LocationGetterDelegate @required - (void) newPhysicalLocation:(CLLocation *)location; @end @interface LocationGetter : NSObject { CLLocationManager *locationManager; id delegate; } - (void)startUpdates; @property (nonatomic, retain) CLLocationManager *locationManager; @property(nonatomic , retain) id delegate; @end
// LocationGetter.m // CoreLocationExample // // Created by Matt on 9/3/10. // Copyright 2009 iCodeBlog. All rights reserved. // #import "LocationGetter.h" #import <coreLocation/CoreLocation.h> @implementation LocationGetter @synthesize locationManager, delegate; BOOL didUpdate = NO; - (void)startUpdates { NSLog(@"Starting Location Updates"); if (locationManager == nil) locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; // locationManager.distanceFilter = 1000; // update is triggered after device travels this far (meters) // Alternatively you can use kCLLocationAccuracyHundredMeters or kCLLocationAccuracyHundredMeters, though higher accuracy takes longer to resolve locationManager.desiredAccuracy = kCLLocationAccuracyKilometer; [locationManager startUpdatingLocation]; } - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Your location could not be determined." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; [alert show]; [alert release]; } // Delegate method from the CLLocationManagerDelegate protocol. - (void)locationManager:(CLLocationManager *)manage didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { if (didUpdate) return; didUpdate = YES; // Disable future updates to save power. [locationManager stopUpdatingLocation]; // let our delegate know we're done [delegate newPhysicalLocation:newLocation]; } - (void)dealloc { [locationManager release]; [super dealloc]; } @end
Next we need to actually invoke this code and start getting location updates. I usually do this in my AppDelegate’s didFinishLaunchingWithOptions, though you could also do it in viewDidLoad somewhere if you didn’t need to know the user’s location on app startup.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; spinner.center = CGPointMake(self.viewController.view.frame.size.width / 2, self.viewController.view.frame.size.height / 2); [spinner startAnimating]; [viewController.view addSubview:spinner]; // get our physical location LocationGetter *locationGetter = [[LocationGetter alloc] init]; locationGetter.delegate = self; [locationGetter startUpdates]; // Add the view controller's view to the window and display. [window addSubview:viewController.view]; [window makeKeyAndVisible]; return YES; }
// // CoreLocationExampleAppDelegate.h // CoreLocationExample // // Created by Matt Tuzzolo on 9/3/10. // Copyright iCodeBlog 2010. All rights reserved. // #import <uikit/UIKit.h> #import "LocationGetter.h" @class CoreLocationExampleViewController; @interface CoreLocationExampleAppDelegate : NSObject { UIWindow *window; CoreLocationExampleViewController *viewController; CLLocation *lastKnownLocation; } @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet CoreLocationExampleViewController *viewController; @property (nonatomic, retain) CLLocation *lastKnownLocation; @end
# pragma mark - # pragma mark LocationGetter Delegate Methods - (void)newPhysicalLocation:(CLLocation *)location { // Store for later use self.lastKnownLocation = location; // Remove spinner from view for (UIView *v in [self.viewController.view subviews]) { if ([v class] == [UIActivityIndicatorView class]) { [v removeFromSuperview]; break; } } // Alert user UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Location Found" message:[NSString stringWithFormat:@"Found physical location. %f %f", self.lastKnownLocation.coordinate.latitude, self.lastKnownLocation.coordinate.longitude] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; [alert show]; [alert release]; // ... continue with initialization of your app }
Now build and run your app and you should see: