Mathias Lund
Mathias Lund

Reputation: 51

mapview random annotation image

I'm having great trouble figuring out what I'm doing wrong here... I am adding annotations to my mapview through loops, but the annotation image is completely random every time... when I NSLog the order, it's random - i'm not sure if that is the problem.

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

    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;

    if ([[annotation subtitle] isEqual:@"Bar"]) {

        MKAnnotationView *view = nil;

        view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"myAnnotationIdentifier"];
        if (!view) {
            // Could not reuse a view ...

            // Creating a new annotation view
            view = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"myAnnotationIdentifier"];


            view.enabled = YES;
            view.canShowCallout = YES;
            view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            view.image = [UIImage imageNamed:@"beer.png"];
        }

        return view;
    }
    else if ([[annotation subtitle] isEqual:@"Club"]) {

        MKAnnotationView *view = nil;

        view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"myAnnotationIdentifier"];
        if (!view) {
            // Could not reuse a view ...

            // Creating a new annotation view
            view = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"myAnnotationIdentifier"];


            view.enabled = YES;
            view.canShowCallout = YES;
            view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            view.image = [UIImage imageNamed:@"clubs.png"];
        }

        return view;
    }
}

the view.image is totally random... either clubs.png or beer.png.. How do I make it correctly?

this is how I add the annotations:

- (void)barLoop {

    for (int i = 0; i<barArray.count; i++) {

        int index = [[barArray objectAtIndex:i]intValue];

        NSString *lati = [[[self.usersLocationArray objectAtIndex:index]
                           valueForKeyPath:@"items.Latitude"]componentsJoinedByString:@""];
        NSString *longi = [[[self.usersLocationArray objectAtIndex:index]
                            valueForKeyPath:@"items.Longitude"]componentsJoinedByString:@""];
        NSString *barNavn = [[[self.usersLocationArray objectAtIndex:index] valueForKeyPath:@"items.Navn"]componentsJoinedByString:@""];


        float latitude = [lati floatValue];
        float longitude = [longi floatValue];

        MKCoordinateRegion region = { {0.0, 0.0} , {0.0, 0.0} };
        region.center.latitude = latitude;
        region.center.longitude = longitude;
        region.span.longitudeDelta = 0.20f;
        region.span.latitudeDelta = 0.20f;
        [mapView setRegion:region animated:NO];

        CLLocationCoordinate2D location;
        location.latitude = latitude;
        location.longitude = longitude;
        Annotation *ann = [[Annotation alloc]initWithPosition:location];
        ann.title = barNavn;
        ann.subtitle = @"Bar";
        [self.mapView addAnnotation:ann];
    }
}

thanks in advance :)

Upvotes: 2

Views: 1000

Answers (1)

Rob
Rob

Reputation: 438232

You have two types of annotations, but you are only setting the image when the annotation is originally created. Thus, if an annotation for a bar scrolls off the map view and another annotation for a club scrolls on, it might reuse the bar's annotation view for the club.

There are two ways of fixing this:

  1. Use different reuseIdentifier parameters for each of the two types of annotation views; or

  2. Set/reset the annotation view's image regardless of whether your call to dequeueReusableAnnotationViewWithIdentifier succeeded in returning a value or not.


Unrelated, but your viewForAnnotation method should:

  1. You might want to use isEqualToString instead of isEqual when checking for @"Bar" vs @"Club".

  2. Make sure to return nil if neither of those if clauses return true (this should never happen, but nonetheless you have a potential path in this routine in which you neglect to return any value). I would guess that this would have been brought to your attention if you ran the code through the static analyzer ("Analyze" on Xcode's "Product" menu).

  3. A more subtle observation, but I'd probably not rely upon the annotation's subtitle for determining which annotation view to employ, but rather either

    • have two annotation subclasses, one for bars and one for clubs; or

    • have a custom property in your existing Annotation class that indicates whether it's a bar or club (and I'd probably use an enum for that).

    At some future date, you might want to use the callout's subtitle for something other than "Bar" vs "Club" (e.g., maybe the address of the bar/club?), and the current model seems to conflate a UI attribute (i.e. what shows up in the callout) with a state property (i.e. a variable that controls which annotation view type to use). Not a big deal, but just an suggestion.

Upvotes: 3

Related Questions