1
votes

I have an annotation view setup that adds a UIButton to rightCalloutAccessoryView. What I am trying to do is set the title of the button to the objectID of the parse object that the annotation represents.

My current result is that every annotation is getting the objectID of the first object in the query. What am I doing wrong here?

Looking at the code below what I am finding is that restaurantID is not being set each time a pin drops on the map. It seems to me I have it in the correct place as the title and subtitle of the pins update correctly.

Here is what I have done:

1.) In my mainViewController.h I have declared a string to hold the objectID of the PFobject:

@property (strong, nonatomic) NSString *restaurantID;

2.) In my mainViewController.m I have synthesized the variable

@synthesize restaurantID;

3.) In my PFquery I am setting this restaurantID to the objectID of the PFobject ( restaurantID = [object objectId];):

 for (PFObject *object in objects) {
            PFGeoPoint *point = [[object objectForKey:@"geoLocation"] init];

            CLLocationCoordinate2D spot;
            spot.latitude = point.latitude;
            spot.longitude = point.longitude;
            MKPointAnnotation *foodPoint = [[MKPointAnnotation alloc] init];
            foodPoint.coordinate = (spot);
            restaurantID = [object objectId];
            foodPoint.title = [object objectForKey:@"restaurantName"];
            foodPoint.subtitle = [object objectForKey:@"cuisineType"];
            leftIcon = [object objectForKey:@"restaurantImage"];
            [leftIcon getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
                if (!error) {
                    image = [UIImage imageWithData:data];
                    // image can now be set on a UIImageView
                }
            }];
            [self.mainMap addAnnotation:foodPoint];
        }

Then in my annotation view I set the title of the button to be the restaurantID:

UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:restaurantID forState:UIControlStateNormal];
[rightButton addTarget:self
                action:@selector(buttonMethod:)
      forControlEvents:UIControlEventTouchUpInside];

In my buttonMethod: I have an NSLog to display the title of the button pressed. The value remains the same as I click on different pins. It grabs the objectID of one Parse object, but it is not grabbing a new objectID for each object in the query.

Any ideas?

1

1 Answers

1
votes

The viewForAnnotation delegate is not necessarily called immediately after you call addAnnotation nor is it necessarily called only once for each annotation.

The map view will call the delegate method when it wants to show the annotation. This may happen a little later than when you add it or it could happen again for the same annotation if the user pans or zooms the map and the annotation comes onto the screen again.

Therefore, you cannot use the view-controller-level restaurantID variable the way you are (by assuming that it was just set in relation to the annotation the map view is calling viewForAnnotation for). By the time the map view calls viewForAnnotation, restaurantID is set to some value that is unrelated to the annotation the map view is currently getting the view for.


Instead, you should put the objectId (or even the whole object) in each annotation individually.

Right now, since you're using the MKPointAnnotation class, the only properties you can set are coordinate, title, and subtitle.

You need to subclass MKPointAnnotation or create your own custom class that implements the MKAnnotation protocol and add a restaurantID property to it.

Set this property when adding the annotation:

CustomAnnotationClass *foodPoint = [[CustomAnnotationClass alloc] init];
foodPoint.coordinate = (spot);
foodPoint.restaurantID = [object objectId]; //<--put objectId in foodPoint
foodPoint.title = [object objectForKey:@"restaurantName"];

Then in viewForAnnotation, use the annotation parameter to get the values relevant to the annotation the map view is currently calling for:

//first make sure annotation is our custom type...
if ([annotation isKindOfClass:[CustomAnnotationClass class]])
{
    UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];

    //cast annotation parameter to our class so compiler understands...
    CustomAnnotationClass *fp = (CustomAnnotationClass *)annotation;

    //get restaurantID from the annotation parameter ("fp")...
    [rightButton setTitle:fp.restaurantID forState:UIControlStateNormal];

    ...
}

Also be sure to handle annotation view re-use properly. That is, if dequeue returns a view, update its annotation property to the current one (eg. annotationView.annotation = annotation;). If this is not done, it's again possible for the view or callout to show data for a different annotation.


That should resolve the issue with the button showing the wrong title.

However, I assume you're setting the button's title just so you can figure out which annotation the user tapped. That will "work" but it's a bit kludgy since the title (restaurantID) will appear to the right of the disclosure icon (though it may not be visible in the callout).

Instead of that approach, I highly recommend using the map view's calloutAccessoryControlTapped delegate method or the map view's selectedAnnotations property. See these questions for examples:

This way, you can get a reference to the annotation object itself and from that get the restaurantID (same way as in viewForAnnotation).