2011-01-23 19 views
10

que tiene una vista de mapa con una gran cantidad de anotaciones (3000 +), cuando el usuario se amplia a un nivel razonable todo está bien y rápido.el manejo de grandes cantidades de MKMapView Anotaciones

Aunque cuando el usuario aleja la vista y una gran cantidad de anotaciones aparecen a la vista, se produce una gran desaceleración debido a la gran cantidad de anotaciones que se muestran a la vez. ¿Cuál es la mejor manera de manejar esto?

La solución actual que estoy usando:

- (void)mapView:(MKMapView *)_mapView regionDidChangeAnimated:(BOOL)animated { 

    NSArray *annotations = [_mapView annotations]; 
    MapAnnotation *annotation = nil; 

    for (int i=0; i<[annotations count]; i++) 
    { 
     annotation = (MapAnnotation*)[annotations objectAtIndex:i]; 
     if (_mapView.region.span.latitudeDelta > .010) 
     { 
      [[_mapView viewForAnnotation:annotation] setHidden:YES]; 
      warningLabel.hidden = NO; 
     } 
     else { 
      [[_mapView viewForAnnotation:annotation] setHidden:NO]; 
      warningLabel.hidden = YES; 
     } 
    } 
} 

Funciona muy bien aunque debido al gran tamaño del bucle esto provoca una gran cantidad de desaceleración al acercar y alejar y desplazar la pantalla. Parece que no puedo pensar en una mejor manera de manejar esto, ¿hay alguna manera de recorrer solo las anotaciones que se muestran actualmente o algo así para reducir el tamaño del ciclo?

Respuesta

7

Según entiendo su código, está ocultando todas las vistas de las anotaciones si la vista de mapa se aleja más de un determinado valor especificado.

Me parece que algo más parecido a la siguiente sería mejor:

- (void)mapView: (MKMapView*)_mapView regionDidChangeAnimated: (BOOL)animated 
{ 
    if (_mapView.region.span.latitudeDelta > .010 && self.mapViewsHidden == NO) { 
     for (MapAnnotation* annotation in _mapView.annotations) { 
      [[_mapView viewForAnnotation: annotation] setHidden: YES]; 
     } 
     [self.warningLabel setHidden: NO]; 
     [self setMapViewsHidden: YES]; 
    } 
    else if (_mapView.region.span.latitudeDelta <= .010 && self.mapViewsHidden == YES) { 
     for (MapAnnotation* annotation in _mapView.annotations) { 
      [[_mapView viewForAnnotation: annotation] setHidden: NO]; 
     } 
     [self.warningLabel setHidden: YES]; 
     [self setMapViewsHidden: NO]; 
    } 
} 

Con lo anterior, en la mayoría de los casos, la única cosa que este código hace un par de si los controles.

Otra solución sería eliminar las anotaciones cuando no deberían mostrar en el mapa. Personalmente, creo que esto sería mejor, así el código no tiene que crear vistas para anotaciones que aún no se han mostrado en el mapa.

+0

Esto aceleró las cosas :) Lo implementaré junto con algunas de las sugerencias de Donkim y todo debería ser muy rápido. – Alex

+0

Hola, ¿qué debo hacer en setMapViewsHidden? Ocultar esas anotaciones? – Misha

+0

MapViewsHidden es una propiedad BOOL. –

6

que sugeriría un par de cosas. Uno, mira el método annotationsInMapRect:. De acuerdo con los documentos, dice:

Este método ofrece una forma rápida de recuperar los objetos de anotación en una parte determinada del mapa. Este método es mucho más rápido que hacer una búsqueda lineal de los objetos en la propiedad de anotaciones usted mismo.

Dos, mira dequeueReusableAnnotationViewWithIdentifier:. De acuerdo con los documentos de nuevo, dice:

Por motivos de rendimiento, generalmente debe reutilizar los objetos MKAnnotationView en las vistas del mapa. A medida que las vistas de anotación se desplazan fuera de la pantalla, la vista de mapa las mueve a una cola de reutilización gestionada internamente. A medida que se mueven las nuevas anotaciones en la pantalla y se solicita al código que proporcione una vista de anotación correspondiente, siempre debe intentar dequear una vista existente antes de crear una nueva. El dequeueing ahorra tiempo y memoria durante las operaciones críticas de rendimiento, como el desplazamiento.

Finalmente, un par de pensamientos. En lugar de hacer estos cambios cada vez que se llama al método - (void)mapView:(MKMapView *)_mapView regionDidChangeAnimated:(BOOL)animated, ¿qué tal si lo hace de acuerdo con alguna otra regla (como después de disparar un temporizador [asegúrese de reiniciar el temporizador cada vez que se llame])? Otra cosa a considerar: ¿qué hay de agrupar las anotaciones que están muy cerca unas de otras? Digamos que estás alejándote de donde Rhode Island parece súper pequeña, tal vez solo una docena de píxeles de ancho, y tienes 100 puntos en Rhode Island; solo debes mostrar un pin.

Espero que esto ayude!

+0

Hola, Donkim, ya tengo dequeueReusableAnnotationViewWithIdentifier: en su lugar, pero voy a buscar en las otras técnicas que sugieres para tratar de que todo funcione más rápido. Es una pena que las anotacionesInMapRect solo se admita en> 4.2, parece que resolvería todos mis problemas – Alex

+0

En mi experiencia, dequeueReusableAnnotationViewWithIdentifier nunca devuelve una anotación antigua. – malhal

+0

annotationsInMapRect es de hecho mucho más rápido que el cálculo de coordenadas usted mismo. – Skoua

2

Terminé agrupando mis anotaciones en clústeres usando OCMapView. Es gratis y muy fácil de implementar en el código existente.

Agrupa automáticamente las anotaciones cuando se aleja el zoom y, al acercarlas, aparecen agrupadas como deberían.

Sé que esta es una vieja pregunta, pero es una gran opción para cualquier persona que intente hacer lo mismo.

+0

Gracias por volver a visitar esta vieja pregunta. Siempre es bueno señalar bibliotecas útiles que ayudarán a resolver el problema, incluso si la respuesta ya está aceptada. –

Cuestiones relacionadas