Hello There: A CoreLocation Tutorial

By
On February 5, 2009

There are plenty of different places to get a mobile application designed. The problem is that they’re quite expensive. You might be able to figure out how to create your own, but it will probably look very basic. Instead, a good mobile application development software can make it even easier, so that you can build great looking apps all by yourself.

The Mobile design Starter Kit includes all the themes and scenarios you need to build whatever app you want. There are customizable and standard files that allow you to sell or offer anything you want through the kit. Everything is there, so once you spend the money, you can create as many mobile apps as you want – and even sell the apps if this is your thing.


 

This tutorial provides a step-by-step howto for using CoreLocation in an iPhone app.

When you’ve finished the tutorial you’ll have created a simple, single-view app with a label that will be updated to show the location. Essentially, you’ll create a simplified version of Apple’s LocateMe sample app, which was the basis for this code.

This tutorial, combined with our earlier Apple Approved Inter-Process Communication post, accounts for all of the inner workings of Alocola, our Safari location helper.

Source/Github

The code for this tutorial is available in GitHub. If you want to follow along in the code, clone the repository:

  1. Open a terminal and change to the directory where you want the code
  2. Clone the repo by typing git clone git://github.com/dcgrigsby/hellothere.git

I’ve made two separate commits to the repository to match the progress of the tutorial. If you’re following along step-by-step you’ll want to revert to the earlier commit:

  1. Type git checkout 655a84c654e25a1ff38492ab61f5e89bd73032bb

Creating The Project

Launch Xcode and create a new View-Based iPhone application called HelloThere:

  1. Create a new project using File > New Project… from Xcode’s menu
  2. Select View-Based Application from the iPhone OS > Application section, click Choose…
  3. Name the project as HelloThere and click Save

Core Location Fundamentals

Core Location is event based. The phone triggers an update event when Core Location is running and a new location becomes available. To use Core Location, you configure your application to receive these update events.

Applications configure where update events are sent by creating an instance of the CLLocationManager class, assigning a CLLocationManagerDelegate — a class instance that will receive the location update events — to it, and enabling location updates.

Creating A Core Location Controller Class

We’ll start by adding the CoreLocation framework to the project:

  1. In the Groups & Files panel of the project, expand the HelloThere project branch
  2. Control-click or right-click the Frameworks folder
  3. Choose Add > Existing Frameworks…
  4. Expand the Frameworks folder
  5. Choose CoreLocation.framework and click Add
  6. Click Add once more

Next, import the CoreLocation headers into the project in HelloThere_Prefix.pch:

  1. In the Groups & Files panel of the project, expand the HelloThere project branch
  2. Expand the Other Sources folder
  3. Click HelloThere_Prefix.pch
  4. Update the file to include a CoreLocation import:

 

#ifdef __OBJC__
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    #import <CoreLocation/CoreLocation.h>
#endif

 

Now, we’ll create a class to handle location events. Later, we’ll wire the location data provided by this class into our view.

Add a new class called MyCLController to the project:

  1. In the Groups & Files panel of the project, expand the HelloThere project branch
  2. Control-click or right-click the Classes folder
  3. Choose Add > New File…
  4. Select NSObject subclass from the iPhone OS &bt; Cocoa Touch Classes section, click Next…
  5. Name the class MyCLController.m and click Finish

Use this code for MyCLController.h:

 

@interface MyCLController : NSObject <CLLocationManagerDelegate> {
	CLLocationManager *locationManager;
}

@property (nonatomic, retain) CLLocationManager *locationManager;

- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation;

- (void)locationManager:(CLLocationManager *)manager
       didFailWithError:(NSError *)error;

@end

 

This .h file: (1) labels our class as adhering to CLLocationManagerDelegate protocol, which enables it to receive location event call backs; (2) contains an instance of the CLLocationManager class — this will be used to register itself as a delegate for events and to activate location updates.

Finally, we’ll finish up the class by adding its implementation:

 

#import "MyCLController.h"

@implementation MyCLController

@synthesize locationManager;

- (id) init {
    self = [super init];
    if (self != nil) {
        self.locationManager = [[[CLLocationManager alloc] init] autorelease];
        self.locationManager.delegate = self; // send loc updates to myself
    }
    return self;
}

- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation
{
    NSLog(@"Location: %@", [newLocation description]);
}

- (void)locationManager:(CLLocationManager *)manager
           didFailWithError:(NSError *)error
{
	NSLog(@"Error: %@", [error description]);
}

- (void)dealloc {
    [self.locationManager release];
    [super dealloc];
}

@end

 

The init method: (1) initializes the location manager and (2) tells the location manager to send updates to this class.

locationManager:didUpdateToLocation:fromLocation and locationManager:didFailWithError are the callback methods that will be triggered by location events. For now, they just add output to the console/log.

Using The Core Location Controller Class

Now that we’ve got a class that should be able to receive updates we ought to see if it works. We’ll add an instance of it to our View Controller and activate it after the view launches.

Use this code for HelloThereViewController.h:

 

#import <UIKit/UIKit.h>
#import "MyCLController.h"

@interface HelloThereViewController : UIViewController {
    MyCLController *locationController;
}

@end

 

Use this code for HelloThereViewController.m:

 

#import "HelloThereViewController.h"

@implementation HelloThereViewController

- (void)viewDidLoad {
    locationController = [[MyCLController alloc] init];
    [locationController.locationManager startUpdatingLocation];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void)dealloc {
    [locationController release];
    [super dealloc];
}

@end

 

The viewDidLoad method (1) allocates and initializes the location controller instance and (2) actives the location updates by sending the startUpdatingLocation message to the location manager.

Run the application and watch the console for location messages:

  1. Run the project using Build > Build and Run from Xcode’s menu
  2. Show the console using Run > Console from Xcode’s menu

The app will log location events to the console. For best results, run this on an iPhone and not the sim; the sim doesn’t provide real location data and, as far as I’ve ever been able to tell, only ever has one update event.

Before continuing: if you’re following along in the source, and you rolled back to the earlier version, you’ll want to roll forward to the final version:

  1. From the terminal, type git checkout 785b46b337d3b0ecbc5d55b770fe6adf4e536d07

Making The Core Location Controller Class Useful

At this point, our core location controller class isn’t of much use. Outputting the updates to the console was kind of a punt to get us started. Let’s fix that now by updating MyCLController to push location change events back to the class that instantiated it. We’ll ultimately configure our view controller to receive these updates to update the app’s display.

To accomplish this, we’ll define a delegate protocol. It will work like this: a class (e.g., our view) can implement the protocol and register itself as the delegate. When location events occur, the MyCLController instance will trigger methods in the delegate (e.g., our view).

Update the MyCLController.h file. Additions are shown in bold:

 

@protocol MyCLControllerDelegate
@required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
@end

@interface MyCLController : NSObject  {
    CLLocationManager *locationManager;
    id delegate;
}

@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, assign) id  delegate;

- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation;

- (void)locationManager:(CLLocationManager *)manager
       didFailWithError:(NSError *)error;

@end

 

The code sets up our delegate protocol. It has two required methods: one for a location update event and another for an error. For our view controller to receive location updates it will have to implement those two methods. But we’re getting ahead of ourselves.

The code also ads a delegate member. As we’ll see in a bit, this will allow our view controller to register itself to receive location updates.

Update MyCLController.m; changes are bold:

 

#import "MyCLController.h"

@implementation MyCLController

@synthesize locationManager;
@synthesize delegate;

- (id) init {
    self = [super init];
    if (self != nil) {
        self.locationManager = [[[CLLocationManager alloc] init] autorelease];
        self.locationManager.delegate = self; // send loc updates to myself
    }
    return self;
}

- (void)locationManager:(CLLocationManager *)manager
	didUpdateToLocation:(CLLocation *)newLocation
         fromLocation:(CLLocation *)oldLocation
{
    [self.delegate locationUpdate:newLocation];
}

- (void)locationManager:(CLLocationManager *)manager
	   didFailWithError:(NSError *)error
{
    [self.delegate locationError:error];
}

- (void)dealloc {
    [self.locationManager release];
    [super dealloc];
}

@end

 

Displaying Location Updates

We’ll conclude this tutorial by modifying our view controller to support the MyCLControllerDelegate prototocol and then use the location callbacks up update a label that we’ll add to the view.

First, let’s add the label that will show the location to the view. Begin by updating HelloThereViewController.h. Additions shown in bold:

 

#import <UIKit/UIKit.h>
#import "MyCLController.h"

@interface HelloThereViewController : UIViewController {
    IBOutlet UILabel *locationLabel;
    MyCLController *locationController;
}

@end

 

Adding the line above provides us with a mechanism for hooking into the label element we’ll add next in Interface Builder. IBOutlet is a macro that tells the compiler that it needs to wire up this variable to a corresponding UILabel element added WYSIWYG in Interface Builder. In the next step, we’ll add that element and connect the two pieces.

Edit the HelloThereViewController.xib file in Interface Builder:

  1. In the Groups & Files panel of the project, expand the HelloThere project branch
  2. Control-click or right-click the Resources folder
  3. Double-click the HelloThereViewController.xib file

Make sure that the Library, Inspector and View windows are open/visible. If they are not:

  1. Show the Library window using Tools > Library from the menu
  2. Show the Inspector window using Tools > Inspector from the menu
  3. Show the View by clicking the View icon on the HelloThereViewController.xib window

Add the label:

  1. Locate the Label component in the Library window and drag it onto the view
  2. In the View window use the label’s handles to enlarge it to about half the size of the view
  3. In the Inspector window under View Attributes (the left-most tab), set the label’s number of lines to 0.

Setting the label’s number of lines to zero configures the label dynamically size the text to fit within its bounds.

Connect the Interface Builder label the code’s locationLabel. While still in Interface Builder:

  1. Control-click on File’s Owner icon in the HelloThereViewController.xib window
  2. In the resulting pop-up menu, click-and-hold (i.e., don’t unclick) on the right-justified circle in the locationLabel row of the Outlets section
  3. Drag the mouse to the Label in the View. A blue line will connect the two.

Confirm that the two have been connected. The pop-up menu should look like the image on the right. If everything looks right, save the changes and close Interface Builder.

Finally, we’ll need to update the HelloThereViewController to implement the MyCLControllerDelegate protocol and set the label to the location. Update the HelloThereController.h file. Changes are shown in bold:

 

#import <UIKit/UIKit.h>
#import "MyCLController.h"

@interface HelloThereViewController : UIViewController <MyCLControllerDelegate> {
    IBOutlet UILabel *locationLabel;
    MyCLController *locationController;
}

- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;

@end

 

Update the HelloThereController.m file. Changes are shown in bold:

 

#import "HelloThereViewController.h"

@implementation HelloThereViewController

- (void)viewDidLoad {
    locationController = [[MyCLController alloc] init];
    locationController.delegate = self;
    [locationController.locationManager startUpdatingLocation];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void)dealloc {
    [locationController release];
    [super dealloc];
}

- (void)locationUpdate:(CLLocation *)location {
    locationLabel.text = [location description];
}

- (void)locationError:(NSError *)error {
    locationLabel.text = [error description];
}

@end

 

By implementing the MyCLControllerDelegate protocol and registering itself as the delegate, our view controller sets itself up to receive location updates. When its locationUpdate method is fired, it updates the label in our view to show the current location.

Conclusion

Build and run the project and enjoy!

  • kryptomaniac

    I’m trying your walkthrough but do not see a CoreLocation.framework.

    I see: CoreAudio.framework, CoreAudioKit.framework, CoreData…, CoreFoundation…, CoreMIDI…, CoreMidiServer…, CoreServices…, CoreVideo…

    I have Xcode 3.1.2 that I downloaded last weekend.

  • kryptomaniac

    I installed the 2.2.1 SDK and CoreLocation.framework now shows up under “Add Existing Framework”

    Thanks for your blog….

  • Narendar Singh Saini

    Its very nice tutorial. I got the basic behind the Location API. For start up its good enough.
    Thx

  • Puppet

    Thank you VERY much for this fantastic tutorial!!

  • vincent

    Merci beaucoup pour ce tutorial: il m’a fait gagner beaucoup de temps!

    (Thanks a lot for this tutorial: it saved me a lot of time!)

  • http://designiteration.com Ben Franklin

    Dan!

    Thank you! Thank you! Thank you! I was deep into deving my latest game (Jetman Extreme Velocity) when, for the first time, I needed a Lat/Long, and REALLY didn’t want to spend the time in a diversion from my focus (the game!) to wrap my head around CoreLocation. You saved me! This tutorial is PERFECT.

    (Hey! Did I mention I was grateful?)

    Until it’s released, you can see the demo of Jetman on

    Thx again,

    BF

  • http://neilang.com Neil

    Thanks! This is the best tutorial on using CoreLocation I have read so far. Thanks!

  • rpv

    good tutorial, but i have a question have somebody noticed that oldLocation is the same as newLocation at least 2 times in a raw, so it looks like the location provided is not very accurate althought set to the Best accuracy?

  • keith

    Thank you for the great tutorial. I’m curious whether it would be possible to write a simple console application (e.g. on a Jailbroken iPhone) so that it would use the CoreLocation service and print out the coordinate in the terminal as opposed to the UI. Thank you.

  • Pingback: Location Tutorial

  • bongio

    Hi All!
    After build all i have encountered this exception:

    /Users/bongio/Documents/Sviluppo Iphone/HelloThere/Classes/MyCLController.m:35: error: synthesized property ‘delegate’ must either be named the same as a compatible ivar or must explicitly name an ivar

    help me!
    Please

  • Narender Mudgal

    Hi,
    Its a nice tutorial,
    I have one question
    while creating locationManager instance variable you are doing autorelease
    than again in dealloc you are doing
    [self.locationManager release];
    will it not throw double free exception.
    ?????

  • Ramesh

    Hi,
    Thanks for the nice tutorial.

    Ramesh.

  • Lee

    Hi, thanks for the tutorial….one question. I am using the iphone simulator and do not get any updates…not even one… ?????

  • http://www.praveensg.com Praveen

    The best tutorial on the Core Location FW by far. Period. Thanks a bunch :)

  • Gwen

    Thank you for this usefull tutorial.

    To Lee : the simulator doesn’t get a GPS, so no update :)

  • http://www.hunka.in rahul bhargava

    Hello Sir,
    I wish to say you very much thanks for this best tutorial.
    sir i embedded your code in my existing project but i am facing one problem i wish to store that description in a variable so that i can access into my whole project wherever i need .i m making its object instead of viewdidload on button click of my project. And i wish to access that particular description in a global string variable.
    Please help me.

  • http://07hill@ensmp.fr Rom

    thanks for this good tuto!

  • Pingback: iPhone Dev – ulubione – 20 wrze?nia 2009 | appledev.pl

  • http://www.linkedin.com/in/nirajpendal Niraj Pendal

    Thanks, tutorial rocks…Keep it good work..

  • HERO

    Nice one man …. keep posting many examples like this !!!!
    ROCK ON!!!!!

  • Ignacio

    Thanks!! This is a great tutorial!
    For everyone…:
    What do you thing would happen if you change the MyCLController’s delegate somewhere in the timeline?
    (For example, set the delegate, then for some reason 5 seconds later the deleage is changed.)

    Well, since position (latitude and longitude) is not changed (suppose you are not moving or not significantly moving) the second delegate method locationUpdate: will never be called!
    Hence you will not have a location if you change the delegate.

    I suggest to “fetch” last location from MyCLController when delegate is being set. This will ensure you have some valid data in you Location

    Thanks again

  • Andre Leitao

    AWESOME!!! Thank you very much! =D

  • Mat

    Hi, thank you so much for this stupend thread!!…
    i have add this line in the init method:

    self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;

    i know(think) there are several kCLLocationAccuracy constant to define when the locationUpdate is call, like(kCLLocationAccuracyHundredMeters, kCLLocationAccuracyBest, etc..)..

    Does anyone know how many times(in second) is called the locationUpdate function?

    P.S: sorry for my bad english!!

  • http://www.scratchmytail.com ScratchMyTail

    Hi, thanks for the tutorial. I noticed something in the code or actually when testing it in Xcode. I got a warning saying that the MyCLController didn’t implement the CLLocationManagerDelegate.
    ‘MyCLController’ does not implement the ‘CLLocationManagerDelegate’ protocol

    So I think the correct header for the interface should be:
    @interface MyCLController : NSObject

  • church

    can anybody help me?
    this is a perfect tutorial, but i need a programm which sends now the location to a webserver. i’am a absolutely newbie.

    thanks for an answer.

    lg

  • Russell

    Hi I was just wondering how would I get the iPhone to send this data to my server like every 10 seconds?

  • church

    @Russell.. if you have an answer for your problem please let me know, because i also have to know this.

    greets church

  • http://www.brandx.net Jim Pickrell

    Great tutorial! I really enjoyed it and found the explanations good and clear and easy to follow. Thanks!

  • kbizzle

    Great tutorial

  • Pingback: Iphone GPS - iPhone Dev Forums

  • http://www.givp.org givp

    Thank you so much for this. It’s exactly what I was looking for.

  • philippe

    Hello,

    thank you so much for this tutorial.

    but, i have an error, on “MyCLController.m” :s


    ".objc_class_name_CLLocationManager", referenced from:
    literal-pointer@__OBJC@__cls_refs@CLLocationManager in MyCLController.o
    ld: symbol(s) not found
    collect2: ld returned 1 exit status

  • philippe

    I have found my problem.

    I have add “CoreLocation.framework” on my project

    THANK YOU for the tutorial ^^

  • Will

    Great tutorial! I love how you isolated the functionality in the delegate

  • http://www.ayerware.com Victor

    I’m new to iPhone coding and objective-C and have been banging my head against the wall trying to figure out CL for HOURS and in 5 minutes you cleared everything up for me! My code now works perfectly! THANKS!

  • Stutgart

    Thanks for this tutorial. I just have a question. Is there any way to use location data from terminal? I mean i want to build a command-line tool that returns the position without having to use any UI. Thanks

  • http://www.robotwoods.com Robot Woods

    @church, @russell

    You could POST the data something like

    - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation;
    [NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:@"http://www.yoursite.com/yourfile.php"];
    [urlRequest setHTTPMethod:@"POST"];
    [urlRequest setHTTPBody:@"lat=%f&lng=%f",newlocation.latitude, newlocation.longitude];
    [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];

  • http://www.robotwoods.com Robot Woods

    well, I mean:

    - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
    [NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:@"http://www.yoursite.com/yourfile.php"];
    [urlRequest setHTTPMethod:@"POST"];
    [urlRequest setHTTPBody:@"lat=%f&lng=%f",newlocation.latitude, newlocation.longitude];
    [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];}

  • Nishant

    Thank you VERY much for this fantastic tutorial!!