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
178 views
in Technique[技术] by (71.8m points)

iphone - MKMapView annotations changing/losing order?

I have a map view with annotations, and these annotations display a callout. When the callout's disclosure detail button is clicked, it segues into a new view.

My MKAnnotations are a custom class that implements <MKAnnotation>. Let's call that class MyClass. They are stored in an NSMutableArray. During viewdidload of this view, I add each object of MyClass in this array to the map view's annotations. Using the debugger, I can see that once all of this adding is done, the [self.MapView annotations] order is the same as the NSMutableArray.

Now I set another breakpoint within mapView:viewForAnnotation: and check out the order of 1) my NSMutableArray and 2) [self.MapView annotations]. The array is of course in the same order. However, the order of the annotations has been scrambled.

This was a big problem for me, because I needed to use the specific instance of MyClass that the user selected in the next view. AKA, I wanted to look at the annotation, find its index, and then use that to get the same index within the array.

I've now realized that I can just save the annotation directly (coming from an Android background, this was very cool to me). However, I am still conceptually at a loss as to why the order became scrambled. Can someone help me? Code below:

- (void)viewDidLoad
{


    if([fromString isEqualToString:@"FromList"])
        self.navigationItem.hidesBackButton = TRUE;
    else { 
        self.navigationItem.rightBarButtonItem = nil;
    }


    self.array = [MySingleton getArray];
    //set up map

    //declare latitude and longitude of map center
    CLLocationCoordinate2D center;
    center.latitude = 45;
    center.longitude = 45;

    //declare span of map (height and width in degrees)
    MKCoordinateSpan span;
    span.latitudeDelta = .4;
    span.longitudeDelta = .4;

    //add center and span to a region, 
    //adjust the region to fit in the mapview 
    //and assign to mapview region
    MKCoordinateRegion region;
    region.center = center;
    region.span = span;
    MapView.region = [MapView regionThatFits:region];

    for(MyClass *t in self.array){
        [MapView addAnnotation:t];
    }
    [super viewDidLoad];
}



//this is the required method implementation for MKMapView annotations
- (MKAnnotationView *) mapView:(MKMapView *)thisMapView 
             viewForAnnotation:(MyClass *)annotation
{


    static NSString *identifier = @"MyIdentifier";

    //the result of the call is being cast (MKPinAnnotationView *) to the correct
    //view class or else the compiler complains
    MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[thisMapView 
                                                                  dequeueReusableAnnotationViewWithIdentifier:identifier];
    if(annotationView == nil)
    {
        annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
    }

    annotationView.pinColor = MKPinAnnotationColorGreen;

    //pin drops when it first appears
    annotationView.animatesDrop=TRUE;

    //tapping the pin produces a gray box which shows title and subtitle  
    annotationView.canShowCallout = YES;

    UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    annotationView.rightCalloutAccessoryView = infoButton;


    return annotationView;
}
See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

When you call addAnnotation or addAnnotations, the map view adds the reference(s) to its internal list of annotations.

The annotations property of MKMapView simply returns this internal list (whatever type it might be) as an NSArray.

I don't know of any place in the documentation where it states that the annotations property returns the array in the same order that you added the annotations in. If you have showsUserLocation turned on, the array will include that annotation even though you didn't explicitly add it.

You do not need to be concerned about nor should you depend on the order of the objects in the annotations property.

Just a few suggestions regarding the code:

  • Since your array contains objects that implement <MKAnnotation>, instead of looping through it, you can add all the annotations in one shot by calling addAnnotations (plural) and pass it the array
  • In viewForAnnotation, none of the properties you are setting depend on any specific annotation so you can set them all inside the if (av == nil) block. This way you get maximum reuse.
  • Also in viewForAnnotation, after and outside the if, you should set the annotation property of the view to the current annotation. This is in case the view is being reused from another annotation.
  • Finally, in viewForAnnotation, don't assume the annotation will be of type MyClass. If you turn on showsUserLocation, that won't be the case. It's safer to declare the parameter as id<MKAnnotation> and then if necessary check what its class is and then cast it.

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

...