IT tutorials
 
Mobile
 

Iphone Application : Using Address Book, Email, and Maps (part 3) - Using a Map Object

12/9/2012 11:35:32 AM
- Windows 10 Product Activation Keys Free 2019
- How to active Windows 8 without product key
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019

Using a Map Object

You added a MKMapView to your user interface and configured it to show the current location of the device. If you attempted to build and run the app, however, you’ll have noticed that it fails immediately. The reason for this is that as soon as you add the map view, you need to add a framework to support it. For our example application, we also need to add two frameworks to the project: Core Location, which deals with locations; and Map Kit, which displays the embedded Google Map.

Adding the Location and Map Frameworks

In the Xcode project window, right-click the Frameworks group and choose Add, Existing Frameworks from the menu. In the scrolling list that appears, choose the MapKit.framework and CoreLocation.framework items, and then click Add.

Drag the frameworks into the Frameworks group if they don’t appear there automatically.

Next, edit the BestFriendViewController.h interface file so that we have access to the classes and methods in these frameworks. Add these lines after the existing #import lines:

#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

We can now display the MKMapView, work with locations and programmatically control the map.

Controlling the Map Display

Because we already get the display of the map and the user’s current location for “free” with the MKMapView, the only thing we really need to do in this application is take the user’s ZIP code, determine a latitude and longitude for it, and then center and zoom the map on that location.

Unfortunately, neither Map Kit nor Core Location provides the ability to turn an address into a set of coordinates, but Google offers a service that does. By requesting the URL http://maps.google.com/maps/geo?output=csv&q=<address> we get back a comma-separated list where the third and fourth values are latitude and longitude, respectively. The address that we send to Google is very flexible—it can be city, state, ZIP, street—whatever information we provide, Google will try to translate it to coordinates. In the case of a ZIP code, it displays the center of the ZIP code’s region on the map—exactly what we want.

Once we have the location, we need to use center and zoom the map. We do this by defining a map “region,” and then using the setRegion:animated method. A region is a simple structure (not an object) called a MKCoordinateRegion. It has members called center, which is another structure called a CLLocationCoordinate2D (containing latitude and longitude); and span, which denotes note many degrees to the east, west, north, and south of the center are displayed. A degree of latitude is 69 miles. A degree of longitude, at the equator, is 69 miles. By choosing small values for the span within the region (like 0.2), we narrow our display down to a few miles around the center point. For example, if we wanted to define a region centered at 40.0 degrees latitude and 40.0 degrees longitude with a span of 0.2 degrees in each direction, we could write the following:

MKCoordinateRegion mapRegion;
mapRegion.center.latitude=40.0;
mapRegion.center.longitude=40.0;
mapRegion.span.latitudeDelta=0.2;
mapRegion.span.longitudeDelta=0.2;

To center and zoom in on this region in a map object called map, we’d use the following:

[map setRegion:mapRegion animated:YES];

To keep things nice and neat in our application, we’re going to implement all of this functionality in a nice new method called centerMap:showAddress. centerMap:showAddress will take a two inputs: a string, zipCode, (a ZIP code), and a dictionary, fullAddress (an address dictionary returned from the Address Book). The ZIP code will be used to retrieve the latitude and longitude from Google, and then adjust our map object to display it. The address dictionary will be used by the annotation view to show a callout from the annotation pushpin.

Enter the new centerMap method shown in Listing 5 within the BestFriendViewController implementation file.

Listing 5.
 1: - (void)centerMap:(NSString*)zipCode showAddress:(NSDictionary*)fullAddress {
 2:     NSString *queryURL;
 3:     NSString *queryResults;
 4:     NSArray *queryData;
 5:     double latitude;
 6:     double longitude;
 7:     MKCoordinateRegion mapRegion;
 8:
 9:     queryURL = [[NSString alloc]
10:                 initWithFormat:
11:                 @"http://maps.google.com/maps/geo?output=csv&q=%@",
12:                 zipCode];
13:
14:     queryResults = [[NSString alloc] initWithContentsOfURL:
15:                     [NSURL URLWithString:queryURL]
16:                         encoding: NSUTF8StringEncoding
17:                         error: nil];
18:     // Autoreleased
19:     queryData = [queryResults componentsSeparatedByString:@","];
20:
21:     if([queryData count]==4) {
22:         latitude=[[queryData objectAtIndex:2] doubleValue];
23:         longitude=[[queryData objectAtIndex:3] doubleValue];
24:         //     CLLocationCoordinate2D;
25:         mapRegion.center.latitude=latitude;
26:         mapRegion.center.longitude=longitude;
27:         mapRegion.span.latitudeDelta=0.2;
28:         mapRegion.span.longitudeDelta=0.2;
29:         [map setRegion:mapRegion animated:YES];
30:
31:         if (zipAnnotation!=nil) {
32:             [map removeAnnotation: zipAnnotation];
33:         }
34:         zipAnnotation = [[MKPlacemark alloc]
35:               initWithCoordinate:mapRegion.center addressDictionary:fullAddress];
36:         [map addAnnotation:zipAnnotation];
37:         [zipAnnotation release];
38:     }
39:
40:     [queryURL release];
41:     [queryResults release];
42:
43: }

					  

Let’s explore how this works. We kick things off in lines 2–7 by declaring several variables we’ll be needing: queryURL, queryResults, and queryData will hold the Google URL we need to request, the raw results of the request, and the parsed data, respectively. The latitude and longitude variables are double-precision floating-point numbers that will be used to store the coordinate information gleaned from queryData. The last variable, mapRegion, will be the properly formatted region that the map should display.

Lines 9–12 allocate and initialize queryURL with the Google URL, substituting in the zipCode string that was passed to the method. Lines 14–17 use the NSString method initWithContentsOfURL:encoding:error to create a new string that contains the data located at the location defined in queryURL. We also make use of the NSURL method URLWithString: to turn the queryURL string into a proper URL object. Any errors are disregarded.

Did you Know?

The initWithContentsOfURL:encoding:error method expects an encoding type. The encoding is the manner in which the string passed to the remote server is formatted. For almost all web services, you’ll want to use NSUTF8StringEncoding.


Line 19 uses the NSString method componentsSeparatedByString, which takes a string, a delimiter character, and returns an NSArray that breaks apart the string based on the delimiter. Google is going to hand back data that looks like this: <number>,<number>,<latitude>,<longitude>. By invoking this method on the data using a comma delimiter (,), we get an array, queryData, where the third element contains the latitude and the fourth, the longitude.

Line 21 does a very basic sanity check on the information we receive. If there are exactly four pieces of information found, we can assume the results are valid and lines 22–29 are executed.

Lines 22 and 23 retrieve the strings at indices 2 and 3 of the queryData array and convert them to double-precision floating-point values, storing them in the latitude and longitude variables.

By the Way

Remember, an array’s index starts at 0. We use an index of 2 to access the third piece of data in the array and an index of 3 to access the fourth.


Lines 25–29 define the region of the map to display and then uses setRegion:animated to redraw the map accordingly.

Finally, lines 31–38 handle the annotation. In lines 31–33, we check to see whether an annotation has already been allocated. (This will happen if the person using the app chooses multiple addresses, resulting in the map being redrawn.) If zipAnnotation has already been used, we can call the MKMapView method removeAnnotation to remove the existing annotation. Once removed, we are free to add a new annotation to the map. Lines 34–35 allocate a new place mark, MKPlaceMark, using the point defined by the map object’s center property and described by the address dictionary passed to the method, fullAddress.

With the zipAnnotation placemark defined, we can add it to the map using addAnnotation method in line 36, and then release the placemark object in line 37.

Creating a Pin Annotation View

As it stands now, your map implementation will work, but it really shouldn’t! For the annotation to be displayed, we need to create an instance of an MKAnnotationView. As mentioned earlier, Apple provides a subclass of the MKAnnotationView called MKPinAnnotationView. When you call addAnnotation on the map view object, iOS is automatically creating an instance of the MKPinAnnotationView for you. Technically, however, we’re supposed to do this ourselves in map view’s delegate method mapView:viewForAnnotation. To keep things legit, add the following method to the BestFriendViewController.m implementation file:

1: - (MKAnnotationView *)mapView:(MKMapView *)mapView
2:             viewForAnnotation:(id <MKAnnotation>)annotation {
3:     MKPinAnnotationView *pinDrop=[[MKPinAnnotationView alloc]
4:             initWithAnnotation:annotation reuseIdentifier:@"citycenter"];
5:     pinDrop.animatesDrop=YES;
6:     pinDrop.canShowCallout=YES;
7:     pinDrop.pinColor=MKPinAnnotationColorPurple;
8:     return pinDrop;
9: }

					  

Lines 1–2 define the mapView:viewForAnnotation method as provided by Apple; this code shouldn’t change. Line 3 declares, allocates, and initializes an instance of MKPinAnnotationView using the annotation parameter that iOS sends to the mapView:viewForAnnotation method, along with a reuseIdentifier string. This reuse identifier is a unique identifying string that allows an allocated annotation to be reused in other places. For our purposes, this could be any string you want.

The new pin annotation view, pinDrop, is configured through three properties in lines 5–7. The animatesDrop Boolean property, when true, animates the pin dropping onto the map. The canShowCallout property sets the pin so that it will display additional information in a callout when touched, and, finally, the pinColor, sets the color of the onscreen pin graphic.

Once properly configured, the new pin annotation view is returned to the map view in line 8.

Tying the Map Display to the Address Book Selection

Congratulations! Your code now has the smarts needed to locate a ZIP code on the map, zoom in, and add a pin annotation view! The last piece of magic we need to finish the mapping is to hook it into the address book selection so that the map is centered when a user picks a contact with an address.

Edit the peoplePickerNavigationController:shouldContinueAfterSelectingPerson method, adding the following line

[self centerMap:friendZip showAddress:friendFirstAddress];

immediately following this line:

friendZip = [friendFirstAddress objectForKey:@"ZIP"];

Our application is nearing completion. All that remains is adding the ability to send email to our chosen buddy. Let the implementation begin!

 
Others
 
- Iphone Application : Using Address Book, Email, and Maps (part 2) - Accessing the Address Book
- Iphone Application : Using Address Book, Email, and Maps (part 1)
- Iphone Application : Extending Application Integration
- Introducing Windows Phone 8 : Phone Specifications
- Introducing Windows Phone 8 : A Different Kind of Phone
- iPhone Application Development : Working with Rich Media - Accessing and Playing the iPod Library
- Android Application Development : Initialization in MicroJobs.java (part 2)
- Android Application Development : Initialization in MicroJobs.java (part 1)
- Android Application Development : Initialization Parameters in AndroidManifest.xml
- Iphone Application : Working with Rich Media - Using the Photo Library and Camera
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
programming4us programming4us
 
Popular tags
 
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS