Lapinou
Lapinou

Reputation: 1477

Wrong image MKAnnotationView after refreshed the map

I have a mapview hundreds of annotations. I load annotations in background, and when all annotations are loaded, I call the method: setAnnotations.

I have 6 types of annotations with different pin for each other.

It works well for the first loading. But if I want to refresh the map (because I use a filter), the pin image change.

I saw a similar issue Here, but it seems not working for me.

Here my viewForAnnotation method:

//... 
else if ([annotation isKindOfClass:[CustomAnnotation class]]) {

        CustomAnnotation *singleAnnotation = (CustomAnnotation *)annotation;
        annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"singleAnnotationView"];

        if (!annotationView) {
            annotationView = [[MKAnnotationView alloc] initWithAnnotation:singleAnnotation reuseIdentifier:@"singleAnnotationView"];
            annotationView.canShowCallout = YES;
            annotationView.centerOffset = CGPointMake(0, -20);
            annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        }
        else
            annotationView.annotation = annotation;

// Solution, put it here:
annotationView.image = [UIImage imageNamed:[NSString stringWithFormat:@"pin_%d", singleAnnotation.idType]];
    } 
//...

And here my method I call to load and reload the map:

- (void)loadMapView
{
    UIActivityIndicatorView *a = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    self.mapview.hidden = YES;
    a.center = CGPointMake(160, 240);
    [self.view addSubview:a];
    [a startAnimating];

    NSMutableArray *array = [NSMutableArray new];

    if(self.mapview.annotations.count > 0){
        [self.mapview removeAnnotations:self.mapview.annotations];
        [self.mapview removeOverlays:self.mapview.overlays];
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

        for(MapObjects *obj in [MapRepository shared].repository){

            CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(obj.coord_geo_latitude,obj.coord_geo_longitude);

            CustomAnnotation *annotation = [[CustomAnnotation alloc] initWithCoordinates:coordinate
                                                                               placeName:obj.placeName
                                                                             description:obj.description
idType:obj.idType];

            if(annotation.coordinate.latitude != 0 || annotation.coordinate.longitude != 0)
                [array addObject:annotation];
        }

        dispatch_async(dispatch_get_main_queue(), ^{

            [self.mapview addAnnotations:array];
            [self.mapview zoomToFitMapAnnotations:self.mapview];
            [a stopAnimating];
            self.mapview.hidden = NO;
        });
    });  
}

What I'm doing wrong ?

Any suggestions and help are appreciate. Thank you in advance ;)

Upvotes: 2

Views: 1674

Answers (2)

Jakub
Jakub

Reputation: 13860

You using reusability so (similar like in tableView rows) your images for 1..12..24.. and next will be the same. If you want to customize the images you have to insert your code outside reusability if.

I mean this line shouldn't be in if (!annotationView)

        annotationView.image = [UIImage imageNamed:[NSString stringWithFormat:@"pin_%d", singleAnnotation.idType]];

Upvotes: 1

Jeff Kelley
Jeff Kelley

Reputation: 19071

The problem is that the map view will re-use pins with the same reuse identifier. This is how you’re creating the pins:

annotationView = [[MKAnnotationView alloc] initWithAnnotation:singleAnnotation
                                              reuseIdentifier:@"singleAnnotationView"];

Subsequently, you set the image. There are two potential solutions:

  1. Use a different reuse identifier for each image type. This way, those pins will be cached as needed.
  2. Set the image on the pin after you create it. This way, all of the pins go into the same reuse pool and are customized as needed.

Here’s what #2 would look like:

CustomAnnotation *singleAnnotation = (CustomAnnotation *)annotation;
annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"singleAnnotationView"];

if (!annotationView) {
    annotationView = [[MKAnnotationView alloc] initWithAnnotation:singleAnnotation reuseIdentifier:@"singleAnnotationView"];
    annotationView.canShowCallout = YES;
    annotationView.centerOffset = CGPointMake(0, -20);
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else {
    annotationView.annotation = annotation;
}

annotationView.image = [UIImage imageNamed:[NSString stringWithFormat:@"pin_%d", singleAnnotation.idType]];

Upvotes: 9

Related Questions