iosmkannotationviewmobile-developmentmkpinannotationviewmkpointannotation

MKPointAnnotation title not showing and annotation not draggable


I think those two are related and I'm probably doing something wrong here:

First I'm overriding viewForAnnotation - in order to put my custom Image

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    // we avoid changing the user's location blue point
    if([annotation isKindOfClass: [MKUserLocation class]]) {
      return nil;
    }
    else
    {
    static NSString *SFAnnotationIdentifier = @"SFAnnotationIdentifier";
    MKPinAnnotationView* pinAnnotationView = (MKPinAnnotationView*)[self.mapToPin dequeueReusableAnnotationViewWithIdentifier:SFAnnotationIdentifier];

     if (!pinAnnotationView)
          {
              MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
                                                                 reuseIdentifier:SFAnnotationIdentifier];
                  UIImage *littleImage = [UIImage imageNamed:@"littleImage.png"];
                  // You may need to resize the image here.
                  annotationView.image = littleImage;
              
                  pinAnnotationView.draggable = true;
                  pinAnnotationView.canShowCallout = true;
                  pinAnnotationView.animatesDrop = true;
                  return annotationView;
          }
          else
          {
              pinAnnotationView.annotation = annotation;
          }
          return pinAnnotationView;
    }
    

}

It seems that pinAnnotationView's draggable, canShowCallout and animatesDrop are not working.

Then, I'm calling my method in my viewDidLoad to set the Annotation

-(void) setAnnotation:(NSString*)lat : (NSString*)lng
{
    _mapAnnotation = [[MKPointAnnotation alloc] init];
    CLLocationCoordinate2D coordinateForPin;
    coordinateForPin.latitude = [lat floatValue];
    coordinateForPin.longitude = [lng floatValue];
    [_mapAnnotation setCoordinate:coordinateForPin];
    [_mapAnnotation setTitle:@"sometitle"];
    [_mapToPin addAnnotation:_mapAnnotation];
}

It seems that [_mapAnnotation setTitle:@"sometitle"]; is not working anymore when I'm overriding viewForAnnotation.

Is this the right way to go? I have been browsing but didn't find any solution that could help. Any feedback would be appreciated.


Solution

  • The problem is the accidental reference to the wrong variable name. The pinAnnotationView is nil inside that if statement, so setting properties with that nil reference is a NOOP.

    
    if (!pinAnnotationView) {
        MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
                                                                        reuseIdentifier:SFAnnotationIdentifier];
    
        ...
    
        annotationView.draggable = true;      // not pinAnnotationView
        annotationView.canShowCallout = true;
        annotationView.animatesDrop = true;
    
        return annotationView;
    }
    

    FWIW, if targeting iOS 10 or later, you can register your own class and move your annotation view configuration code into that subclass. Furthermore, in iOS 11 and later you do not need mapView:viewForAnnotation: at all.

    For example, in iOS 11 and later:

    //  MyAnnotationView.h
    
    @import MapKit;
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface MyAnnotationView : MKPinAnnotationView
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    and

    //  MyAnnotationView.m
    
    #import "MyAnnotationView.h"
    
    @implementation MyAnnotationView
    
    - (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
        self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
    
        if (self) {
            ...
    
            self.draggable = true;
            self.canShowCallout = true;
            self.animatesDrop = true;
        }
    
        return self;
    }
    
    @end
    

    And then, in your viewDidLoad, you register this class.

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        [self.mapView registerClass:[MyAnnotationView class] forAnnotationViewWithReuseIdentifier:MKMapViewDefaultAnnotationViewReuseIdentifier];
        ...
    }
    

    You can then remove the mapView:viewForAnnotation: implementation entirely.