-2

When the map is tested through simulator I notice that some annotations display the default pin instead of the customized image. When I go back to the apps Home menu and enter the mapview again the same thing happens with different annotations.

This code present 4 annotations out of 20 that I have which all uses the same code.

-(void)viewDidLoad {

[super viewDidLoad];

_locationManager = [[CLLocationManager alloc] init];
[mapView setDelegate:self];
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];

MKCoordinateRegion test1 = { {0.0, 0.0} , {0.0, 0.0} };
test1.center.latitude = 55.705609;
test1.center.longitude = 13.195707;
[mapView setRegion:test1 animated:YES];

testmap *ann2 = [[testmap alloc] init];
ann2.title = @"test1";
ann2.subtitle = @"Klicka här för mer info";
ann2.coordinate = test1.center;
ann2.name = @"test1";
[mapView addAnnotation:ann2];

MKCoordinateRegion test2 = { {0.0, 0.0} , {0.0, 0.0} }; //ändra ner
test2.center.latitude = 55.710113;
test2.center.longitude = 13.213500;
[mapView setRegion:test2 animated:YES];

testmap *ann3 = [[testmap alloc] init];
ann3.title = @"test2";
ann3.subtitle = @"Klicka här för mer info";
ann3.coordinate = test2.center;
ann3.name = @"test2";
[mapView addAnnotation:ann3];

MKCoordinateRegion test3 = { {0.0, 0.0} , {0.0, 0.0} };
test3.center.latitude = 55.708981;
test3.center.longitude = 13.197266;
[mapView setRegion:test3 animated:YES];

testmap *ann4 = [[testmap alloc] init];
ann4.title = @"test3";
ann4.subtitle = @"Klicka här för mer info";
ann4.coordinate = test3.center;
ann4.name = @"test3";
[mapView addAnnotation:ann4];

MKCoordinateRegion test4 = { {0.0, 0.0} , {0.0, 0.0} }; //ändra ner
test4.center.latitude = 55.705170;
test4.center.longitude = 13.191277;
[mapView setRegion:test4 animated:YES];

testmap *ann5 = [[testmap alloc] init];
ann5.title = @"test4";
ann5.subtitle = @"Klicka här för mer info";
ann5.coordinate = test4.center;
ann5.name = @"test4";
[mapView addAnnotation:ann5];
}

- (MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(id <MKAnnotation>)annotation

{

if ([annotation isKindOfClass:[MKUserLocation class]])
    return nil;
static NSString* AnnotationIdentifier = @"AnnotationIdentifier";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];




if(annotationView)
    return nil;
else
{
    MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation


  reuseIdentifier:AnnotationIdentifier];    annotationView.canShowCallout = YES;
   NSString* thisModelName = ((testmap*)annotation).name;

    if ([thisModelName isEqualToString:@"test1"]) {
    annotationView.image = [UIImage imageNamed:@"test1"];
    UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

        [rightButton setTitle:annotation.title forState:UIControlStateNormal];
        annotationView.rightCalloutAccessoryView = rightButton;
        annotationView.canShowCallout = YES;
        annotationView.draggable = YES;
        annotationView.highlighted = YES;

    return annotationView;
    }
    else if ([thisModelName isEqualToString:@"test2"])
    {
        annotationView.image = [UIImage imageNamed:@"test2"];
        UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        [rightButton addTarget:self action:@selector(myButton:) forControlEvents:UIControlEventTouchUpInside];
        [rightButton setTitle:annotation.title forState:UIControlStateNormal];
        annotationView.rightCalloutAccessoryView = rightButton;
        annotationView.canShowCallout = YES;
        annotationView.draggable = YES;
        annotationView.highlighted = YES;
        return annotationView;
    }
    else if ([thisModelName isEqualToString:@"test3"])
    {
        annotationView.image = [UIImage imageNamed:@"test3"];
        UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        [rightButton addTarget:self action:@selector(myButton:) forControlEvents:UIControlEventTouchUpInside];
        [rightButton setTitle:annotation.title forState:UIControlStateNormal];
        annotationView.rightCalloutAccessoryView = rightButton;
        annotationView.canShowCallout = YES;
        annotationView.draggable = YES;
        annotationView.highlighted = YES;
        return annotationView;
    }

     else if ([thisModelName isEqualToString:@"test4"])
    {
        annotationView.image = [UIImage imageNamed:@"test4"];
        UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        [rightButton addTarget:self action:@selector(myButton:) forControlEvents:UIControlEventTouchUpInside];
        [rightButton setTitle:annotation.title forState:UIControlStateNormal];
        annotationView.rightCalloutAccessoryView = rightButton;
        annotationView.canShowCallout = YES;
        annotationView.draggable = YES;
        annotationView.highlighted = YES;
        return annotationView;
    }
    }


     return nil;


     }
Ben
  • 91
  • 1
  • 6
  • Does this issue come from if and else? – Ben May 12 '15 at 11:15
  • 1
    It's not necessary to create and set a region just to set an annotation coordinate. You could just do `ann2.coordinate = CLLocationCoordinate2DMake(55.705609, 13.195707);`. Only call setRegion (or showAnnotations) once after adding all the annotations to display that area on the map. –  May 12 '15 at 12:18

1 Answers1

1

You're getting default pins "randomly" because of this code:

MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];

if (annotationView)
    return nil;

What this code says is if the dequeueReusableAnnotationViewWithIdentifier: returns a view (ie. if annotationView is not nil), return nil from the delegate method.


When you return nil from the viewForAnnotation delegate method, the map view does the following:

  • If the annotation is of type MKUserLocation, it will display the default blue dot.
  • If the annotation is not an MKUserLocation, it will display the default red pin.

What you probably meant was:

MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];

if (annotationView)
    return annotationView;

However, this will create a new problem because if the dequeue returns a view (a view that was previously used for a different annotation), the image of the dequeued view might not match the image that should be used for the current annotation.

So what will happen is annotation images will switch around "randomly" as you zoom and pan the map.

The proper approach in viewForAnnotation is to:

  1. Get a reference to a view using dequeueReusableAnnotationViewWithIdentifier: and if that returns nil, create a new view. Set view properties that are common to all annotations only when creating a new view.
  2. Using the view reference obtained in step 1, set view properties that are specific to the current annotation. If a dequeued view is being used, update its annotation property as well.

Example:

- (MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(id <MKAnnotation>)annotation
{
    if (! [annotation isKindOfClass:[testmap class]])
    {
        //If annotation is NOT a "testmap" (eg. MKUserLocation),
        //return nil so map view displays default view for it...
        return nil;
    }

    static NSString* AnnotationIdentifier = @"AnnotationIdentifier";

    MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];

    if (! annotationView) {
        annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
        //set view properties common to all annotations...
        annotationView.canShowCallout = YES;
        UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        //Do not use addTarget with a custom method for callout accessories.
        //Instead, use the calloutAccessoryControlTapped delegate method shown below.
        annotationView.rightCalloutAccessoryView = rightButton;
        annotationView.draggable = YES;
    }
    else {
        //reusing a view, update its annotation to current...
        annotationView.annotation = annotation;
    }

    //AFTER we have a view reference, set annotation-specific properties...
    NSString* thisModelName = ((testmap*)annotation).name;

    if ([thisModelName isEqualToString:@"test1"]) {
        annotationView.image = [UIImage imageNamed:@"test1"];
    }
    else if ([thisModelName isEqualToString:@"test2"]) {
        annotationView.image = [UIImage imageNamed:@"test2"];
    }
    else if ([thisModelName isEqualToString:@"test3"]) {
        annotationView.image = [UIImage imageNamed:@"test3"];
    }
    else if ([thisModelName isEqualToString:@"test4"]) {
        annotationView.image = [UIImage imageNamed:@"test4"];
    }
    /*
     If image name will always be same as `name` property then
     can use single line instead of if/else statements:

         annotationView.image = [UIImage imageNamed:thisModelName];
     */

    return annotationView;
}

-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
    if ([view.annotation isKindOfClass:[testmap class]]) {
        testmap *tm = (testmap *)view.annotation;
        NSLog(@"button for '%@' tapped", tm.name);
    }
}