Create the Project and Design the Interface

First, create a new Xcode project using the Single View Template. Let’s name the project as “MyLocationDemo” and set the project with the following parameters:

MyLocationDemo Xcode Project

Once you’ve successfully created your project, go to the Storyboard and design the user interface. In the View, add three labels for latitude, longitude and address. For each label, place another label next to it. Later we’ll use these labels to display the GPS coordinates and address. Finally, insert a button and name it as “Get My Location”. Your user interface should be similar to the one shown below.

MyLocationDemo User Interface

For the “For Address” label, change the “lines” option from 1 to 4, as we’ll display address in multi-lines. You may also decrease the font size to 14 points in the Attribute Inspector.

Customize Address Label

Establish the Connection Between Variables and UI Elements

Next, we’ll connect the UI elements with our code. In the Storyboard, select the view controller and switch to the Assistant Editor.

Show Assistant Editor and Hide Utility Area

Press and hold the control key, click the “For Latitude Value” label and drag it towards the “MyLocationViewController.h”. Place the cursor between the @interface and @end keywords, you should see a prompt that allows you to insert an outlet.

Establish the Connection Between Variables and UI Elements

Name the outlet as “latitudeLabel”.

Create the Instance Variable and Name it as latitudeLabel

Repeat the same procedures and create the outlet for the “For Longitude Value” label and “For Address” label. Finally, create an action method for the “Get My Location” button and name it as “getCurrentLocation”. This method will be invoked when it detects a Touch Up Inside event.

Create a method for Get My Location Button

If you follow us correctly, the code of MyLocationViewController.h should look like below:

1
2
3
4
5
6
7
8
9
#import <UIKit/UIKit.h>

@interface MyLocationViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *latitudeLabel;
@property (weak, nonatomic) IBOutlet UILabel *longitudeLabel;
@property (weak, nonatomic) IBOutlet UILabel *addressLabel;
- (IBAction)getCurrentLocation:(id)sender;

@end

Adding Core Location Framework

To retrieve the current user location, as mentioned earlier, we’ll make use of the CoreLocation framework provided by the iOS SDK. By default, however, the Core Location Framework is not bundled in any Xcode project. We have to add it manually. In the Project Navigator, select the “MyLocationDemo” project. In the Content Area, select “MyLocationDemo” under Targets and click “Build Phases”. Expand “Link Binary with Libraries” and click the “+” button to add the CoreLocation framework.

Add a new library to Your Xcode Project

Adding CoreLocation Framework to Your Project

Jump into the Code

Let’s move onto the core part of this tutorial. Core Location framework, that you’ve just added, allows you to retrieve the user’s current location in the form of latitude and longitude. It can even give you continuous location update if the user is on the move.

Like other libraries in the iOS SDK, Core Location makes use of the delegate pattern. To work with the Core Location framework, our view controller should conform to the CLLocationManagerDelegateprotocol. This protocol defines methods used to receive location and heading updates from a CLLocationManager object.

To let the view controller know about the CLLocationManagerDelegate, you first import the corresponding header file. In the “MyLocationViewController.h”, add the #import statement and implement the “CLLocationManagerDelegate”.

1
2
3
#import <CoreLocation/CoreLocation.h>

@interface MyLocationViewController : UIViewController <CLLocationManagerDelegate>

Now go to the “MyLocationViewController.m”. Declare an instance variable and name it as locationManager.

1
2
3
@implementation MyLocationViewController {
    CLLocationManager *locationManager;
}

The CLLocationManager is the object that provides you the location data.

Add the following code in the viewDidLoad method to instantiate the CLLocationManager object:

1
2
3
4
5
6
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    locationManager = [[CLLocationManager alloc] init];
}

Once you initialize a CLLocationManager object, you can simply call the startUpdatingLocation method to the location service. The service will then continuously send your application a stream of location data.

Add the following code to the getCurrentLocation method, which is hooked up the to “Get My Location” button:

1
2
3
4
5
6
- (IBAction)getCurrentLocation:(id)sender {
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    
    [locationManager startUpdatingLocation];
}

As discussed earlier, the location data is reported to your app via the location manager’s associated delegate object. Here, we assign MyLocationViewController as the delegate object. All the location updates will send to the delegate. To capture the location event, we have to implement the delegate methods as defined in the protocol.

Add the following code to MyLocationViewController.m and place them right below the “getCurrentLocation” method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma mark - CLLocationManagerDelegate

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"didFailWithError: %@", error);
    UIAlertView *errorAlert = [[UIAlertView alloc]
                                    initWithTitle:@"Error" message:@"Failed to Get Your Location" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [errorAlert show];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    NSLog(@"didUpdateToLocation: %@", newLocation);
    CLLocation *currentLocation = newLocation;
    
    if (currentLocation != nil) {
        longitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
        latitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
    }
}

Test Your App with Fake Location

Now you can compile the app and test it by using the Simulator. You may wonder how you can use the iPhone Simulator to test location-aware application. How can the Simulator retrieve the current location?

There is no way for the Simulator to get the current location as your computer doesn’t have GPS built-in (even you have, Xcode won’t use it). However, the Simulator allows you to fake it.

After you launch the app, click the “Get My Location” button. For the very first time you run the app, it’ll prompt the following alert to request for the access of location manager:

Remember to accept it, otherwise, the app will not be able to access the location service. Oops! The app displays an error even you tap the OK button.

Failed to get the current location

Why? By default, the Simulator doesn’t know its own location. In the menu bar, select “Debug” -> “Location”. The default location is set to “None”. That’s the reason why you get the “Fail to Get Your Location” error. Now change the location setting to “Apple” (or “Apple Stores”). Your app should now show you the latitude and longitude values.

Xcode offers another way to simulate location. While running the app, you can change to other locations by using the arrow button in the top bar of the debug area.

Simulate Other Locations

Finding the Address

The CLGeocoder class provides services for converting between a GPS coordinate and the user-readable address of that coordinate. By specify the latitude and longitude of a given location, you can use CLGeocoder to find a user-readable address. The result (i.e. the address) returned by CLGeocoder is saved in a CLPlacemark object.

Back to your Xcode project. Add two instance variables: geocoder and placemark.

1
2
3
4
5
@implementation MyLocationViewController {
    CLLocationManager *locationManager;
    CLGeocoder *geocoder;
    CLPlacemark *placemark;
}

Initialize the “geocoder” in the “viewDidLoad” method:

1
2
3
4
5
6
7
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    locationManager = [[CLLocationManager alloc] init];
    geocoder = [[CLGeocoder alloc] init];
}

Update the “didUpdateToLocation” method to include the code for reverse geocoding:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    NSLog(@"didUpdateToLocation: %@", newLocation);
    CLLocation *currentLocation = newLocation;
    
    if (currentLocation != nil) {
        longitudeLabel.text = [ NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
        latitudeLabel.text = [ NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
    }
    
    // Reverse Geocoding
    NSLog(@"Resolving the Address");
    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^( NSArray *placemarks,  NSError *error) {
        NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
        if (error == nil && [placemarks count] > 0) {
            placemark = [placemarks lastObject];
            addressLabel.text = [ NSString stringWithFormat:@"%@ %@\n%@ %@\n%@\n%@",
                                 placemark.subThoroughfare, placemark.thoroughfare,
                                 placemark.postalCode, placemark.locality,
                                 placemark.administrativeArea,
                                 placemark.country];
        } else {
            NSLog(@"%@", error.debugDescription);
        }
    } ];

}

We use the “reverseGeocodeLocation” method to translate the locate data into a human-readable address. The geocoding operations doesn’t happen on the device. The method instead submits the given data to the geocoding server in the cloud in order to resolve the address. Other than the location data, you have to provide the handler that contains code to execute after the address is resolved. In this case, we’ll update the address label to display the address on screen.

The syntax of the completionHandler may be new to you. Instead of using delegate to provide feedback, the CLGeocoder uses “block” to deal with the response. By using block, you do not need to write a separate method. Just provide the code inline to execute after the geocoding call completes.

Upon completion of a geocoding request, the completionHandler will be invoked automatically. The resolved address is saved in CLPlacemark array. Placemark data includes information such as the country, state, city, and street address. So we simply pick the CLPlacemark object from the array and show the address in the address label.

That’s it. Run the app again, pick a location (e.g. Apple) and you should get its address:

Saving Battery Power

The app works but it consumes a lot of power. Why? What the app does is to retrieve the current user’s location. It shouldn’t consume much power, right?

Let’s revisit our code again. Once the user taps the “Get My Location” button, we’ll call up the “startUpdatingLocation” method to retrieve the user’s location.

1
2
3
4
5
6
- (IBAction)getCurrentLocation:(id)sender {
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    
    [locationManager startUpdatingLocation];
}

The problem is that the method will report the location data continuously. It just keeps going and gives location update every second, even the location is unchanged. Take a look at the output of the Debug area. You should have something similar to the below:

1
2
3
4
5
6
7
8
9
10
11
12
2012-09-09 14:32:33.940 MyLocationDemo[13690:c07] didUpdateToLocation: <+37.33240905,-122.03051211> +/- 65.00m (speed -1.00 mps / course -1.00) @ 9/9/12 2:32:33 PM Hong Kong Time
2012-09-09 14:32:33.941 MyLocationDemo[13690:c07] Resolving the Address
2012-09-09 14:32:34.793 MyLocationDemo[13690:c07] didUpdateToLocation: <+37.33240818,-122.03049049> +/- 65.00m (speed -1.00 mps / course -1.00) @ 9/9/12 2:32:34 PM Hong Kong Time
2012-09-09 14:32:34.793 MyLocationDemo[13690:c07] Resolving the Address
2012-09-09 14:32:34.997 MyLocationDemo[13690:c07] Found placemarks: (
    "Apple Inc., Apple Inc., 2 Infinite Loop, Cupertino, CA  95014-2083, United States @ <+37.33270820,-122.03033640> +/- 100.00m, region (identifier <+37.33270823,-122.03021599> radius 58.34) <+37.33270823,-122.03021599> radius 58.34m"
), error: (null)
2012-09-09 14:32:35.792 MyLocationDemo[13690:c07] didUpdateToLocation: <+37.33240773,-122.03047951> +/- 65.00m (speed -1.00 mps / course -1.00) @ 9/9/12 2:32:35 PM Hong Kong Time
2012-09-09 14:32:35.793 MyLocationDemo[13690:c07] Resolving the Address
2012-09-09 14:32:35.973 MyLocationDemo[13690:c07] Found placemarks: (
    "Apple Inc., Apple Inc., 2 Infinite Loop, Cupertino, CA  95014-2083, United States @ <+37.33270820,-122.03033640> +/- 100.00m, region (identifier <+37.33270823,-122.03021599> radius 58.34) <+37.33270823,-122.03021599> radius 58.34m"
), error: (null)

As you can see, the “didUpdateToLocation” is invoked multiple times and it just keeps going on and on.

So how can you tell the location manager to stop from updating the location? You can use the “stopUpdatingLocation” method to disable the location update. For our app, we can stop the location update once we retrieve the current location.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    NSLog(@"didUpdateToLocation: %@", newLocation);
    CLLocation *currentLocation = newLocation;
    
    if (currentLocation != nil) {
        longitudeLabel.text = [ NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
        latitudeLabel.text = [ NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
    }

// Stop Location Manager
    [locationManager stopUpdatingLocation];

NSLog(@"Resolving the Address");
    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
        NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
        if (error == nil && [placemarks count] > 0) {
            placemark = [placemarks lastObject];
            addressLabel.text = [NSString stringWithFormat:@"%@ %@\n%@ %@\n%@\n%@",
                                 placemark.subThoroughfare, placemark.thoroughfare,
                                 placemark.postalCode, placemark.locality,
                                 placemark.administrativeArea,
                                 placemark.country];
        } else {
            NSLog(@"%@", error.debugDescription);
        }
    } ];

}

Try to run the app again and check out the output message in the output area. You should notice that the “didUpdateToLocation” is called once and stopped.

iphone dev Introductory example 5:Get the User Location & Address in iPhone App More articles about

  1. iphone dev Introductory example 7:How to Add Splash Screen in Your iOS App

    http://www.appcoda.com/how-to-add-splash-screen-in-your-ios-app/ What’s Splash Screen? For those who ...

  2. iphone dev Introductory example 6:How To Use UIScrollView to Scroll and Zoom and Page

    http://www.raywenderlich.com/10518/how-to-use-uiscrollview-to-scroll-and-zoom-content Getting Starte ...

  3. iphone dev Introductory example 4:CoreData introduction

    The iPhone Core Data Example Application The application developed in this chapter will take the for ...

  4. iphone dev Introductory example 3:Delete a Row from UITableView

    How To Delete a Row from UITableView I hope you have a better understanding about Model-View-Control ...

  5. iphone dev Introductory example 2:Pass Data Between View Controllers using segue

    Assigning View Controller Class In the first tutorial, we simply create a view controller that serve ...

  6. iphone dev Introductory example 1:Use Storyboards to Build Table View

    http://www.appcoda.com/use-storyboards-to-build-navigation-controller-and-table-view/ Creating Navig ...

  7. iphone Dev Development example 10:How To Add a Slide-out Sidebar Menu in Your Apps

    Creating the Xcode Project With a basic idea about what we’ll build, let’s move on. You can create t ...

  8. iphone Dev Development example 9:Create Grid Layout Using UICollectionView in iOS 6

    In this tutorial, we will build a simple app to display a collection of recipe photos in grid layout ...

  9. iphone Dev Development example 8: Parsing an RSS Feed Using NSXMLParser

    From : http://useyourloaf.com/blog/2010/10/16/parsing-an-rss-feed-using-nsxmlparser.html Structure o ...

Random recommendation

  1. [Q&amp;A] VS Connect SQLServer The server was not found or could not be accessed

    Abnormal information : Refer to the solution : 1: Check whether the following two server names are consistent and correct (VS On ) (SQL Server 2008 R2 On ) 2:VS The setting of the instance name in the following figure has no effect on the exception 3: Confirm to start in the service ...

  2. XLAT transcoding : With DS:【BX+AL】 For address , Extract a byte from memory and send it to AL

    data segment a db ,,,,,,,, b dw ;sum of a table db 11h,22h,33h,44h,55h,66h,77h,88h,99h ends code seg ...

  3. POJ1298_The Hardest Problem Ever_ The most difficult problem _Caesar password _C++

    subject :http://poj.org/problem?id=1298 ok , I can't understand the title …… Give the translation ( The title translation is : The most difficult problem ,233333) This is the teacher's solution : But it doesn't work The quickest way ...

  4. Funsion Charts Study ( One )

    Learn from the official website : http://www.fusioncharts.com/explore/line-area-charts/ Parameters : numvdivlines      number     The vertical line shows vd ...

  5. Android adopt PHP Connect MySQL( be used Json)

    1 download phpnow If there is already mysql You need to change the port On the server machine phpnow The installation directory E:\PHPnow-1.5.5\htdocs So let's make a new one test.php file : The database I use is test ...

  6. java Get... In the method request object

    stay spring In the general class of : HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getReques ...

  7. 《 The illustration HTTP》 Reading notes ( One : Network foundation TCP/IP)

    It's never too late to start reading good books . As a tester , We must master some basic knowledge of network . I hope I can take notes here while reading , Easy to understand and consult in the future . One .TCP/IP Protocol family Computers and network devices should communicate with each other , Both sides must base ...

  8. LEGO The history of Robotics

    1998,cybermaster 1999,RCX 1999,micro scout 2000,scout 2002,spybotics NXT NXT2 EV3

  9. UIGestureRecognizer Learning notes 2

    The concrete subclasses of UIGestureRecognizer are the following: UITapGestureRecognizer UIPinchGest ...

  10. CodeForces 508E Arthur and Brackets greedy

    subject : E. Arthur and Brackets time limit per test 2 seconds memory limit per test 128 megabytes input s ...