Question

I'd like to set an image to MKAnnotationView.
But the image is not reflected. It is normal red pin.

ViewController.m

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "CustomAnnotation.h"
@interface ViewController ()<MKMapViewDelegate>
@end
@implementation ViewController{
    MKMapView* _mapView;
}

- (void)viewDidLoad{
    CustomAnnotation* annotation = [[CustomAnnotation alloc]init];
    annotation.coordinate = CLLocationCoordinate2DMake(35.6699877, 139.7000456);
    annotation.image = [UIImage imageNamed:@"annotation.png"];
    [_mapView addAnnotations:@[annotation]];
}

CustomAnnotation.h

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

@interface CustomAnnotation : MKAnnotationView
@property (readwrite, nonatomic) CLLocationCoordinate2D coordinate;
@property (readwrite, nonatomic, strong) NSString* title;
@end

CustomAnnotation.m

#import "CustomAnnotation.h"
@implementation CustomAnnotation
@end
Was it helpful?

Solution

To use a custom image, you have to create and return an MKAnnotationView in the map view's viewForAnnotation delegate method.

If you don't implement that delegate method, the map view will display a default red pin for the annotations you add (regardless of what class the annotations are).

Here's an example of how you could implement it:

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    if (! [annotation isKindOfClass:[CustomAnnotation class]])
    {
        //if this annotation is not a CustomAnnotation
        //(eg. user location blue dot),
        //return nil so the map view draws its default view for it...
        return nil;
    }

    static NSString *reuseId = @"ann";
    MKAnnotationView *av = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
    if (av == nil)
    {
        av = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
        av.canShowCallout = YES;
        av.image = [UIImage imageNamed:@"annotation.png"];
    }
    else
    {
        av.annotation = annotation;
    }

    return av;
}

Be sure to set the map view's delegate property either in code or connect the outlet in the storyboard/xib. If the delegate is not set, the map view won't call the viewForAnnotation method even if you've implemented it and you'll still get the default red pin.


The addAnnotation and addAnnotations methods are only asking for the annotation model objects (objects that implement the MKAnnotation protocol which mainly consists of the coordinate property).

The views for those annotation model objects must be returned in the viewForAnnotation delegate method.

Even though your CustomAnnotation class doesn't explicitly declare that it conforms to MKAnnotation, it implements a coordinate property, so the map view is able to show it on the map.

The fact that it happens to also be a subclass of MKAnnotationView is something the map view doesn't care about or use from the annotation model object.

Your annotation model object should not be a subclass of MKAnnotationView as it will just lead to confusion. It should just implement the MKAnnotation protocol so it should be a subclass of NSObject<MKAnnotation> (or some other custom class besides NSObject).

Change the CustomAnnotation interface to:

@interface CustomAnnotation : NSObject<MKAnnotation>

Change the title property from strong to copy to match the MKAnnotation protocol:

@property (readwrite, nonatomic, copy) NSString* title;

Since CustomAnnotation is no longer an MKAnnotationView, remove the image = line from viewDidLoad and be sure to set the annotation's title otherwise the callout won't show when you tap on it:

//annotation.image = [UIImage imageNamed:@"annotation.png"];
annotation.title = @"annotation";
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top