MKMapView annotations change / get lost?

I have a map view with annotations, and a callout is displayed in these annotations. When the button for detailed markup disclosure is pressed, it switches to a new view.

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

Now I set another breakpoint in mapView: viewForAnnotation: and check the order 1) of my NSMutableArray and 2) [self.MapView annotations]. The array is, of course, in the same order. However, the annotation order was 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 it to get the same index in the array.

Now I realized that I can just save the annotation directly (coming from the Android background, it was very cool for me). However, I still conceptually do not understand why the order became hacked. Can anybody 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; } 
+6
source share
2 answers

When you call addAnnotation or addAnnotations , the map view adds the link to your internal annotation list.

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

I do not know a single place in the documentation that states that the annotations property returns an array in the same order in which you added the annotations. If you enabled showsUserLocation , the array will include this annotation, even if you have not explicitly added it.

You do not need to worry and should not depend on the order of objects in the annotations property.

A few suggestions regarding the code:

  • Since your array contains objects that implement <MKAnnotation> , instead of <MKAnnotation> over it, you can add all the annotations in one shot by calling addAnnotations (plural) and pass it an array
  • In viewForAnnotation none of the properties you set depends on any particular 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 must set the annotation property of the view to the current annotation. This is the case if the view is reused from another annotation.
  • Finally, in viewForAnnotation do not assume that annotation will be of type MyClass . If you enable showsUserLocation , this will not happen. It is id<MKAnnotation> to declare the parameter as id<MKAnnotation> , and then, if necessary, check what its class is, and then drop it.
+6
source

@Anna, you declare that you should not worry about the order of annotations. This is not true in my case. Some annotations may overlap, and I always need a specific one to be on top of two overlapping views. So the DO order makes sense for annotations, since I hope that - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation is called in the same order I added the annotations.

EDIT: and the solution is here :-)

+1
source

Source: https://habr.com/ru/post/909851/


All Articles