iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides) (23 page)

Read iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides) Online

Authors: Aaron Hillegass,Joe Conway

Tags: #COM051370, #Big Nerd Ranch Guides, #iPhone / iPad Programming

BOOK: iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides)
6.03Mb size Format: txt, pdf, ePub
Being a MapView Delegate

When
Whereami
launches, we want it to find the current location and display it on a map. In the last chapter, you worked directly with Core Location to find the user’s location. Now this won’t be necessary because an instance of
MKMapView
knows how to use Core Location to find the user’s location. All you have to do is set the
showsUserLocation
property of an
MKMapView
to
YES
, and it will find and show the user’s location on the map.

 

After the interface loads, the
WhereamiViewController
is sent the message
viewDidLoad
. This is when you will tell the
MKMapView
to update its location. (We’ll talk about
viewDidLoad
in detail in
Chapter 7
.) Implement this method in
WhereamiViewController.m
.

 
- (void)viewDidLoad
{
    [worldView setShowsUserLocation:YES];
}
 

Now that we have the
MKMapView
to determine the location, we don’t need the
locationManager
to do it. Remove the line of code that tells the
locationManager
to start updating in
WhereamiViewController.m
. Leave the rest of the setup code for the location manager in place.

 
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        locationManager = [[CLLocationManager alloc] init];
        [locationManager setDelegate:self];
        [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
        
[locationManager startUpdatingLocation];
    }
    return self;
}
 

Build and run the application. Once the application launches, the map will display a blue annotation dot on your current location. If you are using the simulator, choose a location to simulate by clicking the
icon in the debugger bar and selecting an option.)

 

Unfortunately, you are looking at a map of the entire world, so the blue dot that identifies your location is the size of Brazil. The application clearly needs to zoom in on the current location to be useful. Let’s figure out when and how we can make it do this.

 

For now, assume there is a

zoom-in-on-location

message you can send to an instance of
MKMapView
. The question is
when
would you send that message? When the application starts, it takes time for the device to determine the location. So you can’t send it in
initWithNibName:bundle:
because you don’t yet know the location to zoom in on. Nor do you want to continually tell the
MKMapView
to zoom its map; that would be inefficient.

 

Instead, how about delegation?
MKMapView
has a
delegate
property that you set to be the instance of
WhereamiViewController
. In
WhereamiViewController.h
, declare that
WhereamiViewController
conforms to the
MKMapViewDelegate
protocol.

 
@interface WhereamiViewController : UIViewController
    , MKMapViewDelegate
>
{
 

The map view will send messages to its delegate when interesting events happen. Perhaps there is a message in the
MKMapViewDelegate
protocol for when the map view finds the user’s location. Finding the location is an interesting event, and it would be the perfect time to

do the zoom.

We can find out if the protocol declares such a message in the Apple documentation.

 
Using the documentation

There’s nothing more important we can teach you than how to use the Apple documentation. So hang on as we tackle – step-by-step – the questions of when and how to display a zoomed-in map of the current location.

 

The documentation is divided into four parts: API Reference, System Guides, Tools Guides, and Sample Code. The API Reference shows you every class, protocol, function, structure, method, and anything else you may use from Cocoa Touch. The System Guides give you high-level overviews and discussion about concepts in Cocoa Touch. The Tools Guide is the manual for
Xcode
and the rest of the developer tools suite.

 

While all four parts are useful, the API Reference is absolutely essential to everyday programming. There are so many classes and methods built into Cocoa Touch that it is impossible for a developer to remember them all. At no point in your iOS developer career will you outgrow the API Reference.

 

From the
Help
menu, choose
Documentation and API Reference
. The organizer window will appear with the
Documentation
item selected (
Figure 5.8
). In the lefthand panel, find the search box at the top. Click the magnifying glass icon in the search box and choose
Show Find Options
to show the
Find Options
panel, which allows you to tailor your search. In the search box, enter
MKMapViewDelegate
.

 

Figure 5.8  Documentation Window

 

When you search for a term, the results from each part of the documentation are listed in the table on the left side of the window. The top section titled
Reference
is the API Reference.

 

Search results from the API Reference are contained in nested categories. Each result has an icon that indicates whether it is a class, a method, a protocol, or something else. Collectively, we call these items
symbols
, and their mappings are shown in
Figure 5.9
.

 

Figure 5.9  Documentation symbol guide

 
 

In your search results, look under the
Reference
heading for an item titled
MKMapViewDelegate
and labeled with a
Pr
icon. Select that item to see the reference page for the
MKMapViewDelegate
protocol (
Figure 5.10
). Then scroll down to the
Tasks
section, which groups the protocol’s methods by their use.

 

Figure 5.10  MKMapViewDelegate protocol reference

 
 

Recall that we’re looking for a method that the
MKMapView
will send its delegate when it has found the user’s location. See anything interesting? How about
mapView:didUpdateUserLocation:
? Blue text in the documentation indicates hyperlinks, so you can click on this method name to get more details (
Figure 5.11
).

 

Figure 5.11  A method in the API Reference

 
 

The documentation confirms that this is the method we need, so go ahead and implement a stub for it in
WhereamiViewController.m
. The code completion should kick in after a few keystrokes; make sure you choose the right method from the choices offered.

 
- (void)mapView:(MKMapView *)mapView
    didUpdateUserLocation:(MKUserLocation *)userLocation
{
// Here we are...  but how do we actually zoom?
}

Now that we know when to zoom, we can turn our attention to the problem of how. To problem-solve in programming, it’s best to start with the goal and what we already know. The goal is to display a map that is zoomed in on the user’s current location. We know that when the
MKMapView
finds the user’s location, it sends the message
mapView:didUpdateUserLocation:
to its delegate. We also know that, in the
mapView:didUpdateUserLocation:
method, a pointer to an
MKUserLocation
instance will be available.

 

In addition, we know from experience that the
MKMapView
does not automatically zoom in when it finds the user’s location, so it must be told to do so. This, of course, means that
MKMapView
must implement a method that zooms in on a location. Let’s track down this method in the API Reference.

 

Search for the
MKMapView
class. In the class reference page, look for
Manipulating the Visible Portion of the Map
in the
Tasks
section. There are a handful of methods and properties in this section; we’ll start at the top with the
region
property. The details for
region
tell us that this property is of type
MKCoordinateRegion
and that it provides an implicit zoom. Sounds perfect. But to set this property, we need to know more about
MKCoordinateRegion
.

 

Search for
MKCoordinateRegion
. Its details are in the
Map Kit Data Types Reference
.
MKCoordinateRegion
has two members of types
CLLocationCoordinate2D
and
MKCoordinateSpan
. The
CLLocationCoordinate2D
is the center of the map and the
MKCoordinateSpan
determines the level of zoom (
Figure 5.12
).

 

Figure 5.12  Parts of an MKCoordinateRegion

 

To set the
region
property of the map view, we’ll need to package up one of these instances, so let’s find out how we can do this. Search again for
MKCoordinateRegion
and this time select the
Map Kit Functions Reference
. One of these functions,
MKCoordinateRegionMakeWithDistance
, allows you to specify a region with a
CLLocationCoordinate2D
and the north-south and east-west limits of the zoom in meters. For the limits, we’ll use 250 by 250 meters. For the coordinate, we need the user’s location. Where can we get that?

 

How about the
MKUserLocation
object that the
MKMapView
sends its delegate in the
mapView:didUpdateUserLocation:
message? Search the documentation for
MKUserLocation
, and you’ll find it has a property called
location
that holds the current location of the device. Keep drilling down, and you’ll find that
location
points to a
CLLocation
object, which has a
coordinate
property of type
CLLocationCoordinate2D
. Success! We can use information in the
MKUserLocation
to prepare an
MKCoordinateRegion
, which we then can use to set the
region
property of the map view.

 

From what we know now, getting the information from the
MKUserLocation
takes two steps: we would send
MKUserLocation
the message
location
and then send the returned
CLLocation
object the message
coordinate
. The data returned from
coordinate
then would become the
MKCoordinateRegion
’s
center
.

 

But nosing around the API Reference has its rewards. Before we add this code to
WhereamiViewController.m
, take another look at the
MKUserLocation
reference. At the top, it tells us that
MKUserLocation
conforms to the protocol
MKAnnotation
. Click on the link for that protocol, and you’ll see that classes conforming to it are required to have a property named
coordinate
of type
CLLocationCoordinate2D
. So we can simplify the process and send the message
coordinate
directly to the
MKUserLocation
.

Other books

Balls and Strikes by Michael, Sean
The Evil Beneath by A.J. Waines
Tears of No Return by David Bernstein
Burning Eddy by Scot Gardner
Edge of Hunger by Rhyannon Byrd
Island that Dared by Dervla Murphy
Drawn to You: Volume 3 by Vanessa Booke
Still Mine by Mary Wine
Blood Guilt by Ben Cheetham