altinkonlineConcrete5 Xcode

Attachments

XcodeProject.zip

How to add an annotation to youw mapview


Have you ever dropped a pin on the maps application of your iOS device? This pin is named an annotation.

In this tutorial you would learn to add an annotation to your mapview in a Xcode project.

You could download an example, to add an annotation ot a mapView, from the attachments in the right column.


Start Xcode and create a new project based on the 'Empty Application' template.

Empty-Application.png

Creat a new file based on the 'UIViewController subclass' template. Give the new class a name (we use 'MapViewController') and select subclass of UIViewController.

UIViewController.png

Before we could use CoreLocation and MKMapView we need to add frameworks. Add the frameworks 'CoreLocation' and 'MapKit' to your project.

Adding_Frameworks.png

Open your AppDelegate.m, and import the "MapViewController.h".

// Add this line on top of your AppDelegate.m
#import "MapViewController.h"

Change the application:didFinishLaunchingWithOptions: method in your 'AppDelegate.m' with the code below. First of all create a 'CoreLocationViewController'. Then create a UINavigationController with the 'CoreLocationViewController' as the RootViewController.

Now we need to add the UINavigationController as a subview of the UIWindow.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
 
    MapViewController *myMapViewController = [[MapViewController alloc] 
                                                      initWithNibName:@"MapViewController" 
                                                      bundle:[NSBundle mainBundle]];
 
    UINavigationController *nav = [[UINavigationController alloc] 
                                   initWithRootViewController:myMapViewController];
 
    [[self window] addSubview:[nav view]];
 
    [self.window makeKeyAndVisible];
    return YES;
}

Open your 'MapViewController.xib' and add an object of type MKMapView. Switch to the 'Assistant Editor'. Select the MKMapView and insert an outlet 'myMapView' for this object. You could create outlets by 'ctrl-clicking' a object and drag it to the left side of the 'Assistant Editor'. This two labels are later used to fill with the longitude and latitude of your CoreLocation service.

Now it's time to create your CoreLaction service. We need a CLLocationManager to get thecurrent location of the users device.

Open your 'MapViewController.h' and fill it with the code below. First import the CoreLocation and MapKit services, after that make a CLLocationManager object.

 

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
 
@interface MapViewController : UIViewController <CLLocationManagerDelegate> {
    CLLocationManager *locationManager;
}
 
@property (retain, nonatomic) IBOutlet MKMapView *myMapView;
@property (retain, nonatomic) CLLocationManager *locationManager;
 
@end
 

After that it's time to use the CoreLocation service in your 'MapViewController.m'. Open your file and change or add the methods below. First of all synthesize your before created CoreLocation service.

#import "MapViewController.h"
 
@implementation MapViewController
@synthesize myMapView;
@synthesize locationManager;
 
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

The second change is in the viewDidLoad: method. Initialize your CoreLocation service by changing that method with the code below. 

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
 
    [self setLocationManager:[[CLLocationManager alloc] init]];
    [locationManager setDelegate:self];
    [locationManager setDistanceFilter:kCLDistanceFilterNone]; 
    [locationManager setDesiredAccuracy:kCLLocationAccuracyHundredMeters];
    [locationManager startUpdatingLocation];
}

Now it's time to add the new locationManager:didUpdateToLocation:fromLocation: methodAd the method with the code below. This method is called by the CoreLocation service when the device is going from point a to point b. In this method you've the longitude and latitude, and you could do something with that.

For this time only ad the method. You would add the functionality later.

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
 
}

Before adding an annotation you must create your own MKAnnotation subclass. Creat a new file based on the 'Objective-C class' template. Give the new class a name (we use 'PlaceMark') and select subclass of NSObject.

objective-c_class.png

Open your 'PlaceMark.h' file and fill it with the code below. Create variables to hold the coordinate, title, and subtitle. After that add a new method to set the variables.

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
 
@interface PlaceMark : NSObject <MKAnnotation> {
    CLLocationCoordinate2D coordinate;
    NSString *markTitle, *markSubTitle;
}
 
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, retain) NSString *markTitle, *markSubTitle;
 
-(id)initWithCoordinate:(CLLocationCoordinate2D)theCoordinate andMarkTitle:(NSString *)theMarkTitle andMarkSubTitle:(NSString *)theMarkSubTitle;
 
@end

Open your 'PlaceMark.m' file and fill it with the code below. Synthesize the variables to hold the coordinate, title, and subtitle. Create the new method to set the variables. At least create two methods for MKAnnotation to find your title, and subtitle.

#import "PlaceMark.h"
 
@implementation PlaceMark
@synthesize coordinate;
@synthesize markTitle, markSubTitle;
 
-(id)initWithCoordinate:(CLLocationCoordinate2D)theCoordinate andMarkTitle:(NSString *)theMarkTitle andMarkSubTitle:(NSString *)theMarkSubTitle {
	coordinate = theCoordinate;
    markTitle = theMarkTitle;
    markSubTitle = theMarkSubTitle;
	return self;
}
 
- (NSString *)title {
    return markTitle;
}
 
- (NSString *)subtitle {
    return markSubTitle;
}
 
@end

Now it's time to open again your 'MapViewController.m'. Import the 'PlaceMark.h' on the top of your file.

#import "MapViewController.h"
#import "PlaceMark.h"
 
@implementation MapViewController
@synthesize myMapView;
@synthesize locationManager;

Time to add the functionality to the before added locationManager:didUpdateToLocation:fromLocation: methodFill the method with the code below. First check if location is changed. Create the new coordinate. After that create the region for your mapView. Then you could create and add the PlaceMark.

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
 
    if ((oldLocation.coordinate.longitude != newLocation.coordinate.longitude) 
        || (oldLocation.coordinate.latitude != newLocation.coordinate.latitude)) {
 
        CLLocationCoordinate2D coord = {
            .latitude = newLocation.coordinate.latitude, 
            .longitude = newLocation.coordinate.longitude};
 
        MKCoordinateRegion region;
        region.center = coord;
 
        MKCoordinateSpan span = {.latitudeDelta = 0.2, .longitudeDelta = 0.2};
        region.span = span;
 
        [myMapView setRegion:region];
 
        PlaceMark *placeMark = [[PlaceMark alloc] 
                                initWithCoordinate:coord 
                                andMarkTitle:@"Your first" 
                                andMarkSubTitle:@"placemark"];
 
        [myMapView addAnnotation:placeMark];
    }
}

Now you could add the mapView:viewForAnnotation: method. This is the method that gets called for every annotation you added to the map (like tableView:cellForRowAtIndexPath:), that needs to return the view for each annotation. Add and fill the method with the code below.

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
 
    static NSString *identifier = @"MyLocation";
    if ([annotation isKindOfClass:[PlaceMark class]]) {
 
        MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [myMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
        if (annotationView == nil) {
            annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
        } else {
            annotationView.annotation = annotation;
        }
 
        annotationView.enabled = YES;
        annotationView.canShowCallout = YES;
 
        return annotationView;
    }
 
    return nil; 
}

Now you're ready to run your project! You've succesfully added a annotation on your mapView with the latitude and longitude of your current location.

After this you can read my tutorial how to add an button to an annotation.