MapKit changes the viewing order of annotations when scrolling a map in Xcode 4.6

I am an experienced iOS developer, but it really alarmed me. I am simultaneously reporting an Apple issue.

I am adding annotations to the MKMapKit map (Xcode 4.6). Each annotation is a MyAnnotation class; MyAnnotation defines a property, location_id, which I use to track this annotation.

The problem is simple: I want MyAnnotation with location_id of -1 to appear in front of everything else.

To do this, I override mapView: didAddAnnotationViews: in my MKMapViewDelegate:

-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views { // Loop through any newly added views, arranging them (z-index) for (MKAnnotationView* view in views) { // Check the location ID if([view.annotation isKindOfClass:[MyAnnotation class]] && [((MyAnnotation*)(view.annotation)).location_id intValue]==-1 ) { // -1: Bring to front [[view superview] bringSubviewToFront:view]; NSLog(@"to FRONT: %@",((MyAnnotation*)view.annotation).location_id); } else { // Something else: send to back [[view superview] sendSubviewToBack:view]; NSLog(@"to BACK: %@",((MyAnnotation*)view.annotation).location_id); } } } 

it works great. I have an add button that adds annotation to a random location near the center of my map. Each time I click the add button, a new annotation appears; but nothing hides the annotation with location_id of -1.

** UNTIL ** I'm scrolling!

As soon as I start scrolling, all my annotations are reordered (z-order) and my careful styling no longer applies.

The really confusing thing is that I already did the assembly of the icons, without any problems. I created a brand new application with one view to test this problem; sending MKAnnotationView items to the back or front panel only works until you scroll through the list. There is nothing else in this skeleton app except for the code described above. I am wondering if there is any kind of bug in the latest MapKit infrastructure.

The original problem was trying to add new annotations as the user scrolls (mapView: regionDidChangeAnimated :). Added annotation; mapView: didAddAnnotationViews: code starts; and then the order is scrambled by an invisible hand within the framework (presumably when the scrolling is completed).

In case you are interested, here is my viewForAnnotation:

 -(MKAnnotationView*)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { // Is this an A91Location? if([annotation isKindOfClass:[MyAnnotation class]]){ MyAnnotation* ann=(MyAnnotation*)annotation; NSLog(@"viewForAnnotation with A91Location ID %@",ann.location_id); if([ann.location_id intValue]==-1){ // If the ID is -1, use a green pin MKPinAnnotationView* green_pin=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil]; green_pin.pinColor=MKPinAnnotationColorGreen; green_pin.enabled=NO; return green_pin; } else { // Otherwise, use a default (red) pin MKPinAnnotationView* red_pin=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil]; red_pin.enabled=NO; return red_pin; } } // Everything else return nil; } 

And my class:

 @interface MyAnnotation : NSObject <MKAnnotation> @property (strong, nonatomic, readonly) NSNumber* location_id; @property (strong, nonatomic, readonly) NSString* name; @property (strong, nonatomic, readonly) NSString* description; @property (nonatomic) CLLocationCoordinate2D coordinate; -(id) initWithID:(NSNumber*)location_id name: (NSString*) name description:(NSString*) description location:(CLLocationCoordinate2D) location; // For MKAnnotation protocol... return name and description, respectively -(NSString*)title; -(NSString*)subtitle; @end 
+4
source share
1 answer

Could you try the following:

1) Delete your code in mapView: didAddAnnotationViews:

2) Pickup, when the map is moved or pinched (I assume that this is what you think scrolls to the right?) - I do this with a gesture, not with the mapView area, as I had bad experiences, such as unexplained behavior with last.

 //recognise the paning gesture to fire the didDragMap method UIPanGestureRecognizer* panRec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didDragMap:)]; [panRec setDelegate:self]; [self.mapView addGestureRecognizer:panRec]; //recognise the pinching gesture to fire the didPinchMap method UIPinchGestureRecognizer *pinchRec = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(didPinchMap:)]; [pinchRec setDelegate:self]; //[pinchRec setDelaysTouchesBegan:YES]; [self.mapView addGestureRecognizer:pinchRec]; //recognise the doubleTap UITapGestureRecognizer *doubleTapRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didPinchMap:)]; [doubleTapRec setDelegate:self]; doubleTapRec.numberOfTapsRequired = 2; [self.mapView addGestureRecognizer:doubleTapRec]; 

3) write a custom function "plotAnnotations" to show your annotations. This function will take all your annotations and save them in the "annotationsToShow" array, sorted by your DESC location identifier, so that your location_id -1 will be added last. Use [self.mapView addAnnotations: annotationsToShow]; to display them.

4) Call string Annotations in your gesureRecognizer functions

 - (void)didDragMap:(UIGestureRecognizer*)gestureRecognizer { if (gestureRecognizer.state == UIGestureRecognizerStateEnded){ [self plotAnnotations]; } } - (void)didPinchMap:(UIGestureRecognizer*)gestureRecognizer { if (gestureRecognizer.state == UIGestureRecognizerStateEnded){ [self plotAnnotations]; } } 

5) You may need to remove all annotations before displaying new ones in 3) [self.mapView removeAnnotations: annotationsToRemove];

0
source

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


All Articles