Final App – Mapkit Tutorial For iOS
Prerequisites
- Basic understanding of iOS development
- Some familiarity with protocols ( not necessary but recommended)
MKAnnotation, MKAnnotationView And MKPinAnnotationView
Most of the people slightly familiar with mapkit have doubts regarding these three terms. So I thought why not explain it to beginners at the starting as well. Before we go further, lets look at some theory.
In iOS, maps are created such that data associated with a pin are kept different than the pin views. This is done because if there are thousands of pins/annotations and if all those pins have data along with them, then the OS has to keep all the pins in memory at a time which will slow down your device. So when a pin has to be shown, the OS will look for specific pin coordinate that has to be shown currently on the screen and find the associated data.
The rest of the pins currently not visible on the screen are not kept in memory and when you drag the screen the views of these pins are reused, only the data associated changes. Data for pins are stored in a class that follows MKAnnotation protocol while MKAnnotationView class looks after the views.
MKAnnotation – It is a protocol used to provide annotation related information. It does not provide an visual representation.
MKAnnotationView – This class provides visual representation of the pins. It is loosely paired with annotation data and calls the annotation data whenever required.
MKPinAnnotationView – It is derived from MKAnnotationView and is used if simple pins are required with no major customization such as custom callout view. This can be used for beginners or for a simple app and we are going to use this in our tutorial. In the next tutorial we will directly use MKAnnotationView and make our own custom Pin.
Creating The Project – Mapkit Tutorial for iOS
Create a new project (File->New->Project) and select single view application and name itMapView. Set the class prefix as MV and save the project.
Next, click on the project name in the navigator panel, then click on build phases and addMapKit.Framework to your project in Link Binary with Libraries. Then go to MVViewController.h and replace the entire code with
1
2
3
4
5
6
|
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface MVViewController : UIViewController
@end
|
Setting Up The Views
Go to MainStoryboard.storyboard and drag a map view on the the screen. Position the map view such that it fills the entire screen.
- Make an outlet for this mapview in MVViewController.h and name it mapView.
- Click on your map View in storyboard and then click on the attributes inspector. Tick the check-mark next to Show User Location
Creating the annotation class
Go to File->New->class and select Objective-C class under Cocoa Touch under iOS and click Next. Name the class myAnnotation and subclass as NSObject as shown below
Click Next and save the file.
Replace the code in myAnnotation.h with
1
2
3
4
5
6
7
8
9
10
|
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
//3.1
@interface myAnnotation : NSObject
@property (strong, nonatomic) NSString *title;
@property (nonatomic,assign) CLLocationCoordinate2D coordinate;
-(id) initWithCoordinate:(CLLocationCoordinate2D)coordinate title:(NSString *)title;
@end
|
3.1) We add MKAnnotation protocol since this is the class that will store the data associated with our pins and should follow MKAnnotation protocol. We add two properties to save the data and an initialization method.
Next replace the code in myAnnotation.m with
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#import "myAnnotation.h"
@implementation myAnnotation
//3.2
-(id) initWithCoordinate:(CLLocationCoordinate2D)coordinate title:(NSString *)title {
if ((self = [super init])) {
self.coordinate =coordinate;
self.title = title;
}
return self;
}
@end
|
3.2) We override the default initialization method with this method and set our properties based on the parameters passed in. If you are unable to understand this, we will get back to it later.
Finally We Code!
Go to MVViewController.m and add the following code right at the top of the class after the last import statement
1
2
3
|
#import "myAnnotation.h"
#define METERS_PER_MILE 1609.344
|
We import the class we just made and define a macro which is equal to number of meters in a mile.
Next, add the following method in MVViewController.m
1
2
3
4
5
6
7
8
9
10
|
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//1
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 40.740848;
zoomLocation.longitude= -73.991145;
// 2
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 0.3*METERS_PER_MILE, 0.3*METERS_PER_MILE);
[self.mapView setRegion:viewRegion animated:YES];
}
|
If ViewWillAppear was already present in your code before, remove it.
1)We create a coordinate to be shown when the map is present on the screen the first time. These coordinates are for NewYork.
2)We then create a MKCoordinate region which takes in the coordinate to be shown when the map will appear and aslo takes in the height and the width ( amount of area to be shown, more like zoom). Here we will show 0.3 miles*0.3miles of area centered at zoomLocation and set the region in our mapView outlet.
Add the following code inside viewDidLoad method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//4
self.mapView.delegate = self;
//5
CLLocationCoordinate2D coordinate1;
coordinate1.latitude = 40.740384;
coordinate1.longitude = -73.991146;
myAnnotation *annotation = [[myAnnotation alloc] initWithCoordinate:coordinate1 title:@"Starbucks NY"];
[self.mapView addAnnotation:annotation];
CLLocationCoordinate2D coordinate2;
coordinate2.latitude = 40.741623;
coordinate2.longitude = -73.992021;
myAnnotation *annotation2 = [[myAnnotation alloc] initWithCoordinate:coordinate2 title:@"Pascal Boyer Gallery"];
[self.mapView addAnnotation:annotation2];
CLLocationCoordinate2D coordinate3;
coordinate3.latitude = 40.739490;
coordinate3.longitude = -73.991154;
myAnnotation *annotation3 = [[myAnnotation alloc] initWithCoordinate:coordinate3 title:@"Virgin Records"];
[self.mapView addAnnotation:annotation3];
|
4)We set the mapView delegate to self(this class).
5)Here we set data associated with our pins(title and coordinate in our case). Although this is not the right way to do it, since we will not add data manually but through some jSON or pList file, but for a tutorial’s sake, this is just fine. We declare a coordinate for our pin and set its latitude and longitude. We declare an instance of our custom annotation class and call the init method on it. This is why we made that init method so that we can set the properties at initialization. We finally add the annotation to our mapview outlet. We add two more annotations/pins the same way.
Finally, add the following method right before the last @end statement
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//6
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation {
//7
if([annotation isKindOfClass:[MKUserLocation class]])
return nil;
//8
static NSString *identifier = @"myAnnotation";
MKPinAnnotationView * annotationView = (MKPinAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annotationView)
{
//9
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.pinColor = MKPinAnnotationColorPurple;
annotationView.animatesDrop = YES;
annotationView.canShowCallout = YES;
}else {
annotationView.annotation = annotation;
}
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
|
6) This is a delegate method for mapView which asks us to return the View( visual representation) of the pin to be shown and passes us the annotation object for which the view will be created by us.
7) check if the annotation passed is of kind MKUserLocation class, that is, it is not the annotation created by us but the default annotation ( a single blue point marker that shows our current location) and we do not want to show the pin there. So we return nil if this is the case.
8)We create an MKPinAnnotation instance and reuse it if available just like we do it in a tableView cell.
9)We set the properties of our pin (color, animation etc.) and also set a button on the right and finally return the annotationView.
Run the app (Cmd+R) and you should be able to see the map with three pins.
Note: In order to see your current location do the following steps.
- Select the simulator and in the top, select (Debug->Location->Custom Location) and set the latitude as 40.740848 and longitude as -73.991134. Re- Run the app and you should be able to see a sudo custom location.
That’s it!
Source Code – Mapkit Tutorial for iOS
You can download the complete source code here
Feedback and Doubts
Please use the comments section of this post and I will gladly help you resolve your doubts. Yourfeedback is important for us.
What Next
In the next part of this series, we will make custom callout View and annotations for our map application. So go ahead and learn how to do that -
Advanced Mapkit Tutorial For iOS – Custom Callout