Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
229 views
in Technique[技术] by (71.8m points)

mapkit - Issue with Map Annotation and MKMapView in iOS 4.2?

I have a map view with pins that when the user selects a pin it goes to a detail screen for that pin. I also have a table view that when the user selects an item it goes to the same type detail view.

Here's the problem ...

It seems to work fine in everything from 3.1.3 to 4.1. That is the detail view matches with the pin. But I have a user who just upgraded to iOS 4.2 and says that under 4.1 it worked fine, but in 4.2 the pin selection takes him to the detail for a different pin. But in the table view it still works fine.

Is it possible that there was a change in MKMapView in iOS 4.2 that changes how the pinID is selected?

Addition - I have added the relevant parts of viewForAnnotation and checkButtonTapped

- (MKPinAnnotationView *)mapView:(MKMapView *)eMapView viewForAnnotation:(id <MKAnnotation>)annotation {

int postTag = 0;

MKPinAnnotationView *pinView = (MKPinAnnotationView *)[eMapView dequeueReusableAnnotationViewWithIdentifier:@"Pin"];

if(pinView == nil) {

    pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"Pin"];
    pinView.frame = CGRectMake(0, 0, 25, 25);

} else {

    pinView.annotation = annotation;

}   

// Set up the Right callout
UIButton *myDetailButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
myDetailButton.frame = CGRectMake(0, 0, 23, 23);
myDetailButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
myDetailButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;

[myDetailButton addTarget:self action:@selector(checkButtonTapped:) forControlEvents:UIControlEventTouchUpInside];

// Identify which pin is being selected
if ([[annotation title] isEqualToString:@"Current Location"]) {
    postTag = 99999;
} else {
    postTag = [annotation getPinID];

} 

myDetailButton.tag  = postTag;

pinView.rightCalloutAccessoryView = myDetailButton;

pinView.animatesDrop = YES;

// Set to show a callout on the pin
pinView.canShowCallout = YES;

return pinView;
}

// Method to show detail view when the callOut button is selected
- (IBAction) checkButtonTapped: (id) sender {

int nrButtonPressed = ((UIButton *)sender).tag;

if (nrButtonPressed < 99999) {
    if (self.showDetailView == nil) {

        DetailData *tmpViewController = [[DetailData alloc] initWithNibName:@"Detail" bundle:nil];
        self.showDetailView = tmpViewController;
        [tmpViewController release];

    }

    buttonDetail = [[mapView annotations] objectAtIndex:(nrButtonPressed-1)];

    NSMutableArray *tmpArray = [NSMutableArray arrayWithObjects: [buttonDetail getDataI], [buttonDetail getDataII], [buttonDetail getDataIII], [buttonDetail getDataIV], [buttonDetail getDataV], nil];

    self.showDetailView.eventData = [[NSMutableArray alloc] initWithArray:tmpArray copyItems:YES];

    [self.navigationController pushViewController:self.showDetailView animated:YES];

    [self.showDetailView.eventData release];

}

}

As you can see, in checkButtonTapped I record the pin selected then collect the data from the annotation for that pin. The problem seems to be that nrButtonPressed is now incorrect. But it is fine when compiled in 4.1

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In checkButtonTapped, the annotation is being identified using the button's tag. The button's tag is set in viewForAnnotation by calling the custom method getPinID.

The button tag is used as the index into the mapView annotations array. It's not clear how the getPinID method figures out what index it is at in the mapView's annotations array. I'm not sure it's wise to assume an annotation is going to be at a specific index in the array. Even if mapView doesn't shuffle the annotations around, your app might be constantly adding and removing annotations.

Because you are assigning the button as a callout accessory in the annotation view, rather than using a button tag to identify the annotation, you can use the mapView's own mapView:annotationView:calloutAccessoryControlTapped: delegate method.

Instead of doing addTarget on the button and having it call your custom method, remove the call to addTarget and implement calloutAccessoryControlTapped.

In calloutAccessoryControlTapped, you can directly access the annotation using view.annotation. You can also easily check if the annotation is the "user location":

 - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
    {
        if (view.annotation == mapView.userLocation)
            return;

        buttonDetail = (MyCustomAnnotationClass *)view.annotation;

        //show detail view using buttonDetail...
    }

Additionally, in viewForAnnotation, you are creating a button every time even if the view is being re-used. So a re-used annotation view probably ends up getting multiple buttons on top of each other. The button should only be created and set in the if(pinView == nil) section.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...