Here I want to discuss about using map in iOS application

First, import MapKit

ViewController.h

1
#import <MapKit/MapKit.h>

Then make sure your ViewController conform to MKMapViewDelegate

ViewController.h

1
2
3
4
5
@interface ViewController : UIViewController <MKMapViewDelegate>

@property (nonatomic, strong) MKMapView *mapView;
// ...
@end

In your ViewController.m, create and place the map in ViewController

1
2
3
4
5
6
7
8
9
10
11
12
13
// ...
- (void)viewDidLoad
{
[super viewDidLoad];

self.mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 320, 200)];

// don't miss this
self.mapView.delegate = self;
// if you want it to show user's current location
self.mapView.showsUserLocation = YES;
[self.view addSubview:self.mapView];
}

Remember to create a custom object the conform to MKAnnotation, lets call it MyPlace

MyPlace.h

1
2
3
4
5
6
7
8
9
10
@interface MyPlace : NSObject <MKAnnotation>

@property (nonatomic, strong) NSString *placeName;

- (id)initWithJSON:(id)json;

// must implement this if want to make the Pin draggable
- (void)setCoordinate:(CLLocationCoordinate2D)coordinate;

@end

MyPlace.m

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#import "MyPlace.h"

@interface MyPlace ()

@property (nonatomic, assign) double latitude;
@property (nonatomic, assign) double longitude;

@end

@implementation MyPlace

@synthesize placeName = _placeName;
@synthesize latitude = _latitude;
@synthesize longitude = _longitude;

- (id)initWithJSON:(id)json
{
self.placeName = [json valueForKey:@"name"];
self.latitude = [[json valueForKey:@"lat"] doubleValue];
self.longitude = [[json valueForKey:@"lng"] doubleValue];
}

#pragma mark - MKAnnotation
// this will plot the marker to a correct place on map
- (CLLocationCoordinate2D)coordinate
{
return CLLocationCoordinate2DMake(self.latitude, self.longitude);
}

- (void)setCoordinate:(CLLocationCoordinate2D)coordinate
{
self.latitude = coordinate.latitude;
self.longitude = coordinate.longitude;
}

// this will be shown as marker title
- (NSString *)title
{
return self.placeName;
}

// this will be shown as marker subtitle
- (NSString *)subtitle
{
return [NSString stringWithFormat:@"Lat: %.9f, Lng: %.9f", self.latitude, self.longitude];
}

@end

Add markers, center the region

ViewController.m

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
- (void)loadLocation
{
MyPlace *place1 = [[MyPlace alloc] initWithJSON:[NSDictionary dictionaryWithObjectsAndKeys:
@"The place 1", @"name",
@"3.12345", @"lat",
@"101.43219", @"lng",
nil]];
MyPlace *place2 = [[MyPlace alloc] initWithJSON:[NSDictionary dictionaryWithObjectsAndKeys:
@"The place 2", @"name",
@"4.98721", @"lat",
@"101.82665", @"lng",
nil]];
MyPlace *place3 = [[MyPlace alloc] initWithJSON:[NSDictionary dictionaryWithObjectsAndKeys:
@"The place 1", @"name",
@"5.88621", @"lat",
@"100.99811", @"lng",
nil]];

NSArray *places = @[place1, place2, place3];

// centered the region
MKCoordinateRegion region = [self regionForAnnotations:places];
[self.mapView setRegion:region animated:YES];

// NOTE: if doesn't call this method, no marker will be shown
[self.mapView addAnnotations:places];
}

#pragma mark - MKMapViewDelegate
// this method will only be called if addAnnotation method is call
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// check wether is refer to the class you created just now
if ([annotation isKindOfClass:[MyPlace class]]) {
static NSString *identifier = @"MyLocation";
// just like UITableViewCell, also using dequeue reusable
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];

UIButton *rightButton;
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
// make configuration
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.animatesDrop = NO;
annotationView.pinColor = MKPinAnnotationColorGreen;
// provide custom image as marker if you want to
annotationView.image = [UIImage imageNamed:@"IconMarker"];

// optional: make it draggable
annotationView.animatesDrop = YES;
annotationView.draggable = YES;

// optional: you can add a button
rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self action:@selector(placeTouched:) forControlEvents:UIControlEventTouchUpInside];
annotationView.rightCalloutAccessoryView = rightButton;
} else {
annotationView.annotation = annotation;
}
// add a tag with a specific offset
// remember to put this outside, the annotation will be reuse everytime,
// if this is only set on annotation creation, you may have chances to get the wrong info
rightButton.tag = 4000 + ((MyPlace *)annotation).theId;

return annotationView;
}
return nil;
}

// dragged annotation
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState
{
if (newState == MKAnnotationViewDragStateEnding)
{
CLLocationCoordinate2D droppedAt = annotationView.annotation.coordinate;
NSLog(@"Pin dropped at %f,%f", droppedAt.latitude, droppedAt.longitude);
}
}

- (MKCoordinateRegion)regionForAnnotations:(NSArray *)annotations
{
MKCoordinateRegion region;

if ([annotations count] == 0) {
region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.coordinate, 1000, 1000);

} else if ([annotations count] == 1) {
id <MKAnnotation> annotation = [annotations lastObject];
region = MKCoordinateRegionMakeWithDistance(annotation.coordinate, 1000, 1000);

} else {
CLLocationCoordinate2D topLeftCoord;
topLeftCoord.latitude = -90;
topLeftCoord.longitude = 180;

CLLocationCoordinate2D bottomRightCoord;
bottomRightCoord.latitude = 90;
bottomRightCoord.longitude = -180;

for (id <MKAnnotation> annotation in annotations)
{
topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);
topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
}

const double extraSpace = 1.1;
region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) / 2.0;
region.center.longitude = topLeftCoord.longitude - (topLeftCoord.longitude - bottomRightCoord.longitude) / 2.0;
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * extraSpace;
region.span.longitudeDelta = fabs(topLeftCoord.longitude - bottomRightCoord.longitude) * extraSpace;
}

return [self.mapView regionThatFits:region];
}
...

So just call the loadLocation then the markers will shown.

References: