2009-08-11 2 views
13

MISE À JOURMKMapView chargement toutes les vues d'annotation à la fois (y compris ceux qui sont en dehors du courant rect)

Il semble que ce problème a été discrètement corrigé dans iOS 4.3. Jusqu'à présent, la distance considérée comme «assez loin» pour qu'une annotation soit recyclée semblait être des centaines de kilomètres, même avec un zoom très rapproché. Lorsque je crée mon application avec le SDK iOS 4.3, les annotations sont recyclées en fonction de limites plus raisonnables.


Est-ce que quelqu'un d'autre a rencontré ce problème? Voici le code:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(WWMapAnnotation *)annotation { 



// Only return an Annotation view for the placemarks. Ignore for the current location--the iPhone SDK will place a blue ball there. 

NSLog(@"Request for annotation view"); 

if ([annotation isKindOfClass:[WWMapAnnotation class]]){ 



    MKPinAnnotationView *browse_map_annot_view = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"BrowseMapAnnot"]; 



    if (!browse_map_annot_view) { 
     browse_map_annot_view = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"BrowseMapAnnot"] autorelease]; 
     NSLog(@"Creating new annotation view"); 
    } else { 
     NSLog(@"Recycling annotation view"); 
     browse_map_annot_view.annotation = annotation; 
    } 

...

Dès que la vue est affichée, je reçois

2009-08-05 13:12:03.332 xxx[24308:20b] Request for annotation view 
2009-08-05 13:12:03.333 xxx[24308:20b] Creating new annotation view 
2009-08-05 13:12:03.333 xxx[24308:20b] Request for annotation view 
2009-08-05 13:12:03.333 xxx[24308:20b] Creating new annotation view 

et ainsi de suite, pour chaque annotation (~ 60) J'ai ajoutée. La carte (correctement) affiche uniquement les deux annotations dans le rect actuel. Je suis en train de la région viewDidLoad:

if (center_point.latitude == 0) { 
    center_point.latitude = 35.785098; 
    center_point.longitude = -78.669899; 
} 

if (map_span.latitudeDelta == 0) { 
    map_span.latitudeDelta = .001; 
    map_span.longitudeDelta = .001; 
} 

map_region.center = center_point; 
map_region.span = map_span; 

NSLog(@"Setting initial map center and region"); 

[browse_map_view setRegion:map_region animated:NO]; 

L'entrée du journal de la région à régler est imprimé sur la console avant que des vues d'annotation sont demandées. Le problème ici est que puisque toutes les annotations sont demandées à la fois, [mapView dequeueReusableAnnotationViewWithIdentifier] ne fait rien, puisqu'il y a des MKAnnotationViews uniques pour chaque annotation sur la carte. Cela conduit à des problèmes de mémoire pour moi.

Un problème possible est que ces annotations sont regroupées dans un assez petit espace (rayon de ~ 1 mile). Bien que la carte soit agrandie de façon assez étroite dans viewDidLoad (latitude et longitude delta .001), elle charge toutes les vues d'annotations en même temps.

Merci ...

Répondre

14

Qu'est-ce que vous attendez est une sorte de « coupure » des vues d'annotation sur la base du region actuelle les écrans de carte.

Ce n'est PAS le fonctionnement du sélecteur dequeueReusableAnnotationViewWithIdentifier.

Depuis sa documentation: Comme des vues d'annotation se déplacent hors-champ, la vue sur la carte les déplace à une file d'attente de réutilisation gérée en interne. À mesure que de nouvelles annotations se déplacent à l'écran et que votre code est invité à fournir une vue d'annotation correspondante, vous devez toujours tenter de supprimer la mise en file d'attente d'une vue existante avant d'en créer une nouvelle.

Ainsi, le mécanisme réutilisable n'a de sens que lorsque vous invoquez une séquence comme:

 
//this will create 1000 annotation views 
[theMap addAnnotations:my1000annotations]; 
//this will move them offscreen (but some annotation views may be kept internally for further reuse) 
[theMap removeAnnotatios:theMap.annotations]; 
//when adding back again some annotations onscreen, some of the previous annotation views will be reused. 
[theMap addAnnotations:someNew400annotations]; 

En vous cas, la façon dont je mettre en œuvre la coupure (pour afficher uniquement l'annotation pour la région en cours d'affichage) est:

  • Ajouter un délégué à votre Mapview et mettre en œuvre la méthode - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated pour s'informer quand la région a changé
  • itérer à travers tous vos objets pour obtenir ceux qui correspondent à cette région
  • addAnnotations à votre carte uniquement pour les objets (vous pouvez mettre en œuvre une sorte de fusion entre les annotations précédemment affiché et le nouveau ou simplement redémarrer à partir de zéro, supprimer toutes les annotations et définissez les nouveaux

Bien sûr , lorsque l'utilisateur effectue un zoom arrière important et que la portée de la région est trop grande (trop de broches à afficher), alors vous devez prendre une décision: est-ce que j'affiche toutes les vues des annotations (et prend le risque que l'affichage sur la carte ne donne pas beaucoup d'informations) ou est-ce que je mets un message à l'utilisateur en disant "zoom avant pour obtenir des épingles" ou quoi que ce soit. Mais c'est une autre histoire ...;)

+0

Ceci est une excellente réponse. J'avais lu la documentation, mais je suppose que le design de la file d'attente ressemblait à celui de la file d'attente. Avec les cellules de tableau, il semble qu'elles limitent la taille de la file d'attente et commencent à libérer les cellules de la table (je n'ai pas vérifié avec le débogueur, cependant). C'est bizarre que la déchéance sur la carte ne soit pas cohérente avec ça. Je me demande pourquoi, quand la logique de maintenir une liste de marqueurs qui sont à l'intérieur et à l'extérieur de la région actuelle existe déjà dans la classe, le développeur devrait répliquer cela pour obtenir des économies de mémoire réelles. Merci!! – jmans

+0

Hum, oui, vous avez raison, c'est étrange parce que le nom est vraiment comme celui de UITableView, et comme vous l'avez dit, le mot "offscreen" laisse l'utilisateur penser qu'il devrait fonctionner comme UITableView. Et vous avez raison aussi, je pense que si vous créez une vue tabulaire avec une taille de section de 10000, vous n'obtiendrez jamais 10000 UITableViewCellView instanciées car la plupart d'entre elles sont réutilisées. idée supplémentaire: quand définissez-vous les annotations dans votre code? Êtes-vous sûr à 100% qu'il est appelé après avoir défini la valeur de la région? – yonel

+0

Je ne suis pas sûr à 100%, mais je n'aurai plus l'occasion de jouer avec mon code jusqu'à jeudi. Je vais y jeter un autre coup d'oeil, avec votre conseil en tête, et vous faire savoir ce qui se passe. – jmans

0

Je ne sais pas si cela va aider, mais vous avez mentionné les problèmes de mémoire en raison de la charge de 60 ~ objets. Existe-t-il un moyen de charger de manière conditionnelle chaque objet en fonction du centre de la région cartographique actuelle et de l'étendue de la région cartographique actuelle?

// :)

+0

Eh bien, idéalement, c'est ce que dequeueReusableAnnotationViewWithIdentifier devrait faire, je pensais. Je suppose que je pourrais le faire à partir de zéro et gérer un tableau d'emplacements et chaque fois que l'utilisateur effectue un zoom ou un panoramique, obtenir la nouvelle région de la carte, supprimer les régions appropriées, puis ajouter les nouvelles. – jmans

Questions connexes