Using iPhone SDK MapKit Framework – A tutorial

June 22, 2009

Recently I was working on an application in which the map was required to be shown with in the application itself. I tried looking for some online resources that could be of some help but did not find any. I was not able to find any good tutorial that explains how can an address be shown on a map with the application. Therefore, I decided to write one and here it is. Hope it will be of some help.

Lets create a simple application which displays the address entered by the user on the map within the application. We’ll call it MapApp.

  1. First, create a Window based application and name the project as MapApp.
  2. Add the MapKit framework to the project. (Control + Click Frameworks folder -> Add -> Existing Frameworks)
  3. Create a new view controller class and call it MapViewController. Add a text field, button and map view to it.
    #import <UIKit/UIKit.h>
    #import <MapKit/MapKit.h>

    @interface MapViewController : UIViewController<MKMapViewDelegate> {
        IBOutlet UITextField *addressField;
        IBOutlet UIButton *goButton;
        IBOutlet MKMapView *mapView;
    }

    @end

4. Now create a xib file named MapView.xib. Set its type to MapViewController and add a UITextField, UIButton and MKMapView to it. This how it will look like.

MapView.xib

Make sure you set the delegate for the mapView to the controller class.

5. Once the view is ready, update the MapAppDelegate so that the view controller and the view is loaded.

    - (void)applicationDidFinishLaunching:(UIApplication *)application {
        mapViewController = [[MapViewController alloc] initWithNibName:@"MapView" bundle:nil];
        [window addSubview:mapViewController.view];
        [window makeKeyAndVisible];
    }

6. Now, build the app and check if the view appears correctly or not. We now have the UI ready for entering the address and button for updating the location in the map.

7. Add the class for showing the annotation on the location. Lets call this class as AddressAnnotation.

    @interface AddressAnnotation : NSObject<MKAnnotation> {
        CLLocationCoordinate2D coordinate;
        NSString *mTitle;
        NSString *mSubTitle;
    }
    @end

    @implementation AddressAnnotation

    @synthesize coordinate;

    - (NSString *)subtitle{
        return @"Sub Title";
    }

    - (NSString *)title{
        return @"Title";
    }

    -(id)initWithCoordinate:(CLLocationCoordinate2D) c{
        coordinate=c;
        NSLog(@"%f,%f",c.latitude,c.longitude);
        return self;
    }
    @end

This class will basically show the title and the subtitle of the location on the map.

8. Lets add the function that will be called when the ‘Go’ button is tapped and this will contain the code that will actually display the address location on the map. We call that action as showAddress

    - (IBAction) showAddress {
        //Hide the keypad
        [addressField resignFirstResponder];
        MKCoordinateRegion region;
        MKCoordinateSpan span;
        span.latitudeDelta=0.2;
        span.longitudeDelta=0.2;

        CLLocationCoordinate2D location = [self addressLocation];
        region.span=span;
        region.center=location;
        if(addAnnotation != nil) {
            [mapView removeAnnotation:addAnnotation];
            [addAnnotation release];
            addAnnotation = nil;
        }
        addAnnotation = [[AddressAnnotation alloc] initWithCoordinate:location];
        [mapView addAnnotation:addAnnotation];
        [mapView setRegion:region animated:TRUE];
        [mapView regionThatFits:region];
     }

9. The map view basically shows the location based on its latitude and longitude but we have the address in the textual form. Therefore we need to convert this into CLLocationCoordinate2D. Note that in the above code we call the function names addressLocation to perform this conversion.

-(CLLocationCoordinate2D) addressLocation {
    NSString *urlString = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv", 
                    [addressField.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString]];
    NSArray *listItems = [locationString componentsSeparatedByString:@","];

    double latitude = 0.0;
    double longitude = 0.0;

    if([listItems count] >= 4 && [[listItems objectAtIndex:0] isEqualToString:@"200"]) {
        latitude = [[listItems objectAtIndex:2] doubleValue];
        longitude = [[listItems objectAtIndex:3] doubleValue];
    }
    else {
         //Show error
    }
    CLLocationCoordinate2D location;
    location.latitude = latitude;
    location.longitude = longitude;

    return location;
}

The above code reads the address entered in the input box and gets the location from maps.google.com in CSV format. It then gets the latitude and longitude from it. The return code of 200 from google means success.

10. Finally, lets add the delegate function that will display the annotation on the map

- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation{
    MKPinAnnotationView *annView=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"currentloc"];
    annView.pinColor = MKPinAnnotationColorGreen;
    annView.animatesDrop=TRUE;
    annView.canShowCallout = YES;
    annView.calloutOffset = CGPointMake(-5, 5);
    return annView;
}

This function basically creates a annotation view (a green color pin) with the annotation that we added earlier to the MapView. Tapping on the green pin will display the title and the sub-title.

Finally, here’s how the map looks like when loaded.

MapApp1

MapApp2

So this was a very simple example of how a map can be shown from within an application. Hope this was helpful. Let me know your comments/feedback. Click here to download the code.

UPDATE: All this while Google was not looking for API key in the URL - http://maps.google.com/maps/geo?q=address&output=csv

The URL now needs to change to – http://maps.google.com/maps/geo?q=address&output=csv&key=YourGoogleMapsAPIKey

You can obtain your API key here

Entry Filed under: Geeky stuff. Tags: , .

67 Comments Add your own

  • 1. dys  |  July 1, 2009 at 11:14 am

    Thanks for writing this. It works perfectly! There aren’t a lot of MapKit tutorials out there, so I’m glad I found this.

    One minor typo, though. There’s a semi-colon missing from:
    annView.canShowCallout = YES

    Reply
    • 2. mithin  |  July 3, 2009 at 11:32 am

      Thanks. The missing semi-colon is now added.

      Reply
  • 3. paul  |  July 3, 2009 at 7:18 pm

    Hello, really great tutorial! I went step by step through it though and I’m having some trouble getting it to work… i keep getting errors. Would it be possible for you to post the working final version of this project? that would be reallyyyy usefull to someone new to this like myself.

    Thanks in advance!

    Reply
    • 4. apple1  |  July 3, 2009 at 7:24 pm

      I agree, it would be greatly appreciated if you could post a zipped up version of the working project! Thanx

      Reply
      • 5. mithin  |  July 3, 2009 at 10:18 pm

        Paul, Apple1, Thanks for the feedback. I have zipped the project and have shared the link at the end of the post.

  • 6. justmobileprograms  |  July 5, 2009 at 10:43 pm

    thanks for the tutorial

    Reply
  • 7. Gurpartap Singh  |  July 6, 2009 at 2:38 am

    Good stuff!

    PS: MKPinAnnotationView *annView is not released.

    Thanks!

    Reply
  • 8. Koen  |  July 6, 2009 at 11:27 pm

    Thanks! Great tutorial!

    Reply
  • 9. Greg  |  July 7, 2009 at 8:21 pm

    thanks, great tutorial
    It really helped me on this issue

    Reply
  • 10. Doane  |  July 13, 2009 at 8:51 pm

    Brilliant! Very helpful! How would you go about putting multiple pins on the map, and is there a way to navigate to another view when you press on a pin?

    Reply
    • 11. Doane  |  July 14, 2009 at 4:19 pm

      Ok the multiple annotations was fairly obvious, got that!

      But now, for some very strange reason, I can’t change the colour of my pins. I changed it once but now my code isn’t even running through the function that displays the annotation, yet it has trouble displaying it but it simply won’t change the colour. I have no idea what’s happening here, can’t figure it out, maybe something to do with my adding the second annotation.
      Weird!

      Reply
      • 12. mithin  |  July 14, 2009 at 9:04 pm

        Hi Doane!

        Sorry, I might not be able to help you solve your problems because of time constraints. I suggest you post your issues on some iPhone development forum. You are more likely to find a solution there.

      • 13. Doane  |  July 15, 2009 at 8:10 pm

        No problem, I just gotta fiddle with it a bit methinks! It really should be running through that delegate in order to be placing pins on the map I would have thought, don’t know how it works without it and don’t know why it isn’t calling it anyways!

        I’ll let ya know if I figure it out!

      • 14. mike  |  November 24, 2009 at 11:21 pm

        Doane, did you ever figure out how to resolve this?
        I did something to break it but I can’t seem to find how to fix it.

  • 15. Mapkit and function syntax - iPhone Dev Forums  |  July 15, 2009 at 8:39 pm

    [...] Something that's confusing me a little bit, and this feels kinda like a stupid question! I did this tutorial and have since successfully incorporated it into my own project but I don't understand [...]

    Reply
  • 16. Doane  |  July 20, 2009 at 4:58 pm

    How do you change the title and subtitle from outside of the addAnnotation class? If I’m adding a load of annotations I don’t want the same title but I can’t figure out how to change the title property or pass in a variable

    Reply
    • 17. Neill  |  August 22, 2009 at 6:06 pm

      objective-c “singletons” may help, these enable you to store global type variables temporarily. Handy.

      Reply
  • 18. Adam  |  July 20, 2009 at 10:58 pm

    “Make sure you set the delegate for the mapView to the controller class”

    Can someone explain what that really means? I can’t figure out what needs to be done. At stage 6 the app builds and launches in the simulator but nothing is displayed. I had to change one line though to get it to compile:

    mapViewController = [[MapViewController alloc…

    to MapViewController *mapViewController = [[ MapView…

    Reply
    • 19. Doane  |  July 21, 2009 at 7:50 pm

      Do you have this line in your implementation:

      MapViewController *mapViewController;

      Reply
      • 20. gmgm  |  November 7, 2009 at 6:05 pm

        the implementation in the MapViewController file?

        thanks for ur time :)

    • 21. Doane  |  July 23, 2009 at 5:32 pm

      Also, to set the delegate, open your nib, select the map view and look at it’s connections in the inspector, drag from the circle opposite “delegate” to the files owner..

      That’s what that means, and I had made the mistake of not doing that at first which meant it would work but I couldn’t figure out how to change the pincolour..

      Reply
  • 22. Gary  |  July 22, 2009 at 11:34 pm

    Thanks for the tutorial! It is very helpful. But, I’m not able to get the Geocode. My listitem contains only 2 elements. The code is below;

    NSString *urllString = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv",
    [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    NSLog(@”listItems urlString %@”,urllString);
    NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urllString]];
    NSArray *listItems = [locationString componentsSeparatedByString:@","];

    NSLog(@”listItems count %d”,[listItems count]);

    Count here is 2.

    Thanks a bunch!
    Gary

    Reply
    • 23. mithin  |  July 23, 2009 at 9:00 am

      Mostly likely the URL is not right. What happens when you paste the URL in your browser?

      Reply
  • 24. jissa  |  July 23, 2009 at 11:36 am

    Thanks for the samples.
    is there any code to make the pin(MKPinAnnotationView) move when the user drag or touch?

    Reply
  • 25. Doane  |  July 23, 2009 at 5:29 pm

    Why can’t I declare a string in MapViewController? I want to dynamically change the title and subtitle for multiple pins..

    Reply
  • 26. Surendra  |  July 23, 2009 at 6:11 pm

    Thanks for this. It helps me a lot..

    Reply
  • 27. Surendra  |  July 23, 2009 at 6:31 pm

    Can we draw multiple pins using that mapkit framework like pins for different location at same time..
    Please suggest..

    Reply
    • 28. Doane  |  July 23, 2009 at 7:07 pm

      Yeah, you’re just repeating the code to add more and more annotations, like so:

      CLLocationCoordinate2D add1=mapView.userLocation.coordinate;
      CLLocationCoordinate2D add2=mapView.userLocation.coordinate;
      CLLocationCoordinate2D add3=mapView.userLocation.coordinate;
      CLLocationCoordinate2D add4=mapView.userLocation.coordinate;

      add1.latitude=53.278611;
      add1.longitude=-6.243056;
      addAnnotation=[[AddAnnotation alloc] initWithCoordinate:add1];
      [mapView addAnnotation:addAnnotation];

      add2.latitude=53.278333;
      add2.longitude=-6.106944;
      addAnnotation=[[AddAnnotation alloc] initWithCoordinate:add2];
      [mapView addAnnotation:addAnnotation];

      add3.latitude=53.342778;
      add3.longitude=-6.256944;
      addAnnotation=[[AddAnnotation alloc] initWithCoordinate:add3];
      [mapView addAnnotation:addAnnotation];

      add4.latitude=53.380556;
      add4.longitude=-6.288889;
      addAnnotation=[[AddAnnotation alloc] initWithCoordinate:add4];
      [mapView addAnnotation:addAnnotation];

      Reply
      • 29. roger chan  |  January 28, 2010 at 9:01 pm

        I tried this using my derived class of AddAnnotation, but still only 1 pin appears, not sure why.

        add1.latitude=53.278611;
        add1.longitude=-6.243056;
        addAnnotation=[[TheSpaceObject alloc] initWithCoordinate:add1];
        [mapView addAnnotation:addAnnotation];
        add2.latitude=53.278333;
        add2.longitude=-6.106944;
        addAnnotation=[[TheSpaceObject alloc] initWithCoordinate:add2];
        [mapView addAnnotation:addAnnotation];
        add3.latitude=53.342778;
        add3.longitude=-6.256944;
        addAnnotation=[[TheSpaceObject alloc] initWithCoordinate:add3];
        [mapView addAnnotation:addAnnotation];
        add4.latitude=53.380556;
        add4.longitude=-6.288889;
        addAnnotation=[[TheSpaceObject alloc] initWithCoordinate:add4];
        [mapView addAnnotation:addAnnotation];

  • 30. Dustin  |  July 23, 2009 at 8:40 pm

    Thanks for the great tutorial. I have been having trouble with this before finding your tutorial. Here’s a question for you. I want to be able to feed long and lat to the map from a plist located on an online server instead of having the user put in the address. Can this be done? If so, how?

    Thanks,
    D

    Reply
  • 31. Vijay P  |  July 24, 2009 at 8:42 am

    I mostly figured out how to do all of this stuff on my own; but this is a great tutorial. I’m trying to figure out how to get the callout to have a different (larger) size when my subtitle won’t fit in the callout. Is there any way to do this programmatically? I tried changing the view’s frame, but that didn’t seem to work so well.

    Reply
  • 32. Doane  |  July 30, 2009 at 9:01 pm

    How would one put code behind a pin? Say if I want to switch views when the user clicks on a pin?

    Reply
    • 33. nobody  |  August 8, 2009 at 12:15 am

      I have the same question as Doane basically. How would one have the app do something (not related to the map part at all really) when the user touches on a pin?

      Reply
      • 34. Lars-Jørgen Kristiansen  |  August 8, 2009 at 5:08 pm

        Dont know about when the user pushes the pin but you could add a button to the annotation…

        Like this:

        UIButton *annotationButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        [annotationButton addTarget:self action:@selector(annotationAction) forControlEvents:UIControlEventTouchUpInside];
        annView.rightCalloutAccessoryView = annotationButton;

        and put your code in

        - (void) annotationAtion {
        //code here!!
        }

  • 35. iPhone: First map application « My tech blog diary  |  August 8, 2009 at 5:27 am

    [...] Update: I found another tutorial: link. [...]

    Reply
  • [...] for some of the code and the original idea go to http://mithin.in/2009/06/22/using-iphone-sdk-mapkit-framework-a-tutorial/ Share and [...]

    Reply
  • 37. Neill  |  August 22, 2009 at 5:55 am

    First Class Tutorial thanks!
    Still working up to using annotations, a quick way to get the map to a specific region is to get to step 6 and then add the following into your MapViewController.m – (void)viewDidLoad { }

    Simply takes you to specific lat and lon coordinates if thats all you need.

    - (void)viewDidLoad {

    [super viewDidLoad];

    mapView.mapType = MKMapTypeStandard;
    mapView.scrollEnabled = YES;
    mapView.zoomEnabled = YES;
    // mapView.delegate = self;

    CLLocationCoordinate2D coords;
    coords.latitude = 55.948815;
    coords.longitude = -3.194790;
    MKCoordinateSpan span;
    span.latitudeDelta=0.02;
    span.longitudeDelta=0.02;

    mapView.region = MKCoordinateRegionMake( coords, span );

    }

    Cheers

    Reply
  • 38. Shinto Joseph  |  August 31, 2009 at 12:19 pm

    superb Tutorial, thanks

    i like to know , how can i put some custom images instead of the pin (like GIcon in google maps API) and is there any way to show the driving directions between two points ?

    thanks in advance…

    Reply
  • 39. Nilshan  |  August 31, 2009 at 7:15 pm

    This tutorial is really helpful.

    Is there any way load Custom Map ( Hospital Map ) and add
    annotation on that.

    I want to add Hospital Layout Map using MKMapView. In MKMapView I want to add Annotations like chairs , bed. etc.

    Is there any way to get it done. ! Is there any work around to achieve this.

    Thanks,
    Nilshan.

    Reply
  • 40. Mohit  |  September 6, 2009 at 4:45 pm

    This is no doubt awesom tutorail with excellent readability.
    Thanks brother for saving my many working hour for this solution…

    [:)]

    Reply
  • 41. aasdf  |  September 9, 2009 at 6:26 am

    You forgot
    AddressAnnotation *addAnnotation;

    in the declaration in the html-version of the code.. :)

    Thanks for a great tutorial, appreciate your time!

    Reply
  • 42. kish  |  September 22, 2009 at 12:43 pm

    Hi,
    superb tutorial thanks,

    now i have some problem with loading custom information into callout buble instead of title and subtitle…can any one know how to do

    thanks in advance

    Reply
  • 43. tnathos  |  September 23, 2009 at 10:08 pm

    Hi, great tuto.. but how i can put more lines to the subtitle?

    Reply
  • 44. iPhone tutorial Sammlung 1: MapKit « Alexander Jäger  |  September 30, 2009 at 6:15 pm

    [...] http://mithin.in/ sehr gute Lösung [...]

    Reply
  • 45. Daz  |  October 6, 2009 at 9:34 pm

    thanks~~~

    Reply
    • 46. leyarga  |  October 6, 2009 at 11:50 pm

      Hi,
      I have the same problem explained at comment 17. I’m not able to display the map. The simulator can’t display the map and is not able to launch the application!
      Somebody help me please!!!

      Reply
      • 47. leyarga  |  October 7, 2009 at 12:52 am

        I find the solution. mapKit framework was missing and i coudn’t take it from the way discribed at point 2.
        I was having this error:

        Terminating app due to uncaught exception ‘NSInvalidUnarchiveOperationException’, reason: ‘Could not instantiate class named MKMapView’

        The right way to add a framework and to avoid this error is :

        -Double click on project target
        -Go to General
        -Click on +
        -Add the chosen framework

        thanks for this good tutorial

  • 48. Paul  |  October 21, 2009 at 2:21 pm

    Great tutorial thank you!

    A couple of questions:

    1. In your response at [26] how would you go about naming the additional addresses from an array member?

    I’ve tried things like CLLocationCoordinate2D [myArray objectAtIndex:0] but not having any luck.

    2. Are we able to use this code in our own projects?

    Reply
    • 49. Paul  |  October 21, 2009 at 7:56 pm

      OK, so I’ve managed to get the array working (I needed to remove the bit about if annotation is nil)

      But I would love to know how to set the annotation title to something meaningful for each array member?

      Reply
  • 50. Sam  |  October 22, 2009 at 9:49 am

    Hi,
    I ran the code proviced by you but I am getting 610,0,0,0 as the returned error.

    Please let me know what I am doing wrong. I entered Los Angeles in the text box.

    Thanks
    Sam

    Reply
  • 53. Deepak Sahu  |  October 26, 2009 at 4:46 pm

    It is really Great tutorial and helpful
    Thank You!

    Reply
  • 54. Gaurav Jain  |  October 30, 2009 at 7:20 pm

    Hi , I am trying to use the same code but its throwing an error saying : ” expected specifier-qualifier-list before MKMapview”

    Reply
  • 55. gmgm  |  November 7, 2009 at 5:42 pm

    is there a reason that i cant get step 5 to work? i think it is just me being stupid and not doing something, i just cant work it out!!

    It’s saying that ‘mapViewController’ undeclared!

    Please help me someone!?

    Thank you! Great tutorial though :)

    Reply
    • 56. Tarun Sharma  |  November 24, 2009 at 4:21 pm

      hey..
      write in delegate’s header file:
      MapViewController *mapViewController;

      Reply
  • 57. prs  |  November 9, 2009 at 9:38 am

    hey, great tutorial!
    I have a couple of doubts:

    1. What is a protocol as opposed to a class? We had to create AddressAnnotation Class to pass on to MKMapView:addAnnotation instead of passing a direct object of MKAnnotation ?

    2. where does the delegate function in the last step sit in? it is not called not anywhere else. is it embedded inside addAnnotation fucntion?

    Thanks,
    prs

    Reply
  • 58. Mark  |  November 12, 2009 at 6:21 pm

    Excellent tutorial. Thank you so much!

    Reply
  • 59. Andy  |  November 17, 2009 at 12:49 am

    Hi, I’m having the exact same problem as gmgm, when i try to run it in step 6, it says mapViewController and MapViewController are undeclared, any help please I’m desperate?

    Thanks

    Reply
    • 60. mithin  |  November 17, 2009 at 10:43 am

      I just downloaded the code from the download link in the post. The code builds fine without any error. Can you explain your build steps and error?

      Reply
      • 61. Andy  |  November 17, 2009 at 5:53 pm

        Hi i think i figured it out, being unfamiliar with the SDK, i created the /xib file under classes, when i downloaded your code, the xib was under resources, i ran your code and it works fine, cheers.

  • 62. Tarun Sharma  |  November 24, 2009 at 4:04 pm

    hi .. it was an awesome tutorial. I made my first map application using this tutorial..Hats off to u.. great job.

    Reply
  • 63. neha P  |  November 24, 2009 at 5:42 pm

    hello! Simply great… thanx for such a tutorial…!

    Reply
  • 64. mike  |  November 24, 2009 at 11:18 pm

    I am having the same problems as post 11 and 13. It was working fine and now it does not execute the overriden viewForAnnotation method.
    I could change the pin colors, etc. but now it defaults to the standard annotation red and will not execute my viewForAnnotation for customization.

    Doane, did you ever find out how to resolve this??

    Thanks

    Reply
  • 65. Bugle Diary  |  November 26, 2009 at 9:38 pm

    [Objective-C][iPhone sdk][google maps]pinを表示その3…

    UIViewControllerを使わなくてもピンの色を変更して表示できました。プログラムがめちゃくちゃ長いですが、お付き合いください。…

    Reply
  • 66. suresh thorata  |  December 9, 2009 at 12:27 pm

    Hi, that was a useful tutorial.
    Is there any way to show the driving directions between two points ?
    Thanks.

    Reply
  • 67. nextTime  |  January 11, 2010 at 1:02 am

    Two things that would have made this tutorial better. Instructions as to what class files to place certain methods in, you have to end up guessing.
    Also, complete step by step instructions, if you follow this tutorial to the letter it won’t compile, there are so many things missing. If you compare the final code to what the tutorial tells you to do, it’s completely different.

    Reply

Leave a Comment

Required

Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed


Recent Posts

Category Cloud

Food for thought Freelancer Geeky stuff General Humor Inside stories iSight Short n Sweet

On the web

TinyTweets

Archives

Feeds