2009-08-11 7 views
13

UPDATEMKMapView ładuje wszystkie widoki adnotacji naraz (w tym tych, które są poza obecnym rect)

Wygląda jak ten problem został rozwiązany w spokojnej iOS 4.3. Do tego momentu dystans, który uważano za "wystarczająco duży", aby anotacja mogła zostać poddana recyklingowi, wydawała się być setkami mil, nawet przy bardzo dużym zbliżeniu. Gdy buduję swoją aplikację za pomocą pakietu SDK iOS 4.3, adnotacje są przetwarzane w oparciu o bardziej uzasadnione limity.


Czy ktoś inny napotkał ten problem? Oto kod:

- (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; 
    } 

...

Gdy zostanie wyświetlony widok, mam

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 

i dalej i dalej, za każdym adnotacji (~ 60) Mam dodany. Mapa (poprawnie) wyświetla tylko dwie adnotacje w bieżącym rect. Ja ustawienie regionu w 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]; 

Wpis dziennika dla regionu jest ustawiony zostanie wydrukowany do konsoli zanim jakiekolwiek widoki adnotacji są wymagane.

Problem polega na tym, że ponieważ wszystkie adnotacje są żądane natychmiast, [mapView dequeueReusableAnnotationViewWithIdentifier] nic nie robi, ponieważ istnieją unikalne MKAnnotationViews dla każdej adnotacji na mapie. To prowadzi do problemów z pamięcią.

Jednym z możliwych problemów jest to, że te adnotacje są skupione w dość małej przestrzeni (promień ~ 1 mile). Chociaż mapa jest bardzo przybliżona w viewDidLoad (szerokość i długość geograficzna delta .001), wciąż ładuje wszystkie widoki adnotacji naraz.

Dzięki ...

Odpowiedz

14

Czego można oczekiwać jakiś rodzaj „przycinania” poglądów adnotacji na podstawie aktualnego region wyświetlaczy map.

To NIE działa w taki sposób, jak selektor dequeueReusableAnnotationViewWithIdentifier.

Z dokumentacji: jak widoki adnotacji przenieść poza ekranem, widok mapy przesuwa je wewnętrznie zarządzanym kolejce ponownego wykorzystania. Gdy nowe adnotacje zostaną przeniesione na ekran, a twój kod zostanie poproszony o podanie odpowiedniego widoku adnotacji, zawsze powinieneś spróbować usunąć istniejący widok przed utworzeniem nowego.

więc mechanizm wielokrotnego użytku ma sens tylko wtedy, kiedy wywołać sekwencję jak:

 
//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]; 

W Tobie przypadku sposób byłoby wdrożyć wycinek (wyświetlanie tylko adnotacji dla bieżącego wyświetlanego regionu) jest:

  • Dodaj delegata do MapView i wdrożenie metody - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated, aby uzyskać informacje, kiedy region zmieniła
  • iterację wszystkich obiektów, aby uzyskać te, które pasują do tego regionu
  • addAnnotations do mapy tylko dla tych obiektów (można realizować rodzaj scalenia pomiędzy poprzednio wyświetlane adnotacje i nowym lub po prostu ponownie od zera, należy usunąć wszystkie adnotacje i ustaw nowymi

Oczywiście , gdy użytkownik znacznie pomniejszy, a zasięg regionu jest zbyt duży (zbyt wiele szpilek do wyświetlenia), musisz podjąć decyzję: czy wyświetlam wszystkie widoki adnotacji (i podejmuję ryzyko, że wyświetlanie na mapie nie daje zbyt wielu informacji) lub ustawić komunikat dla użytkownika mówiąc "powiększ, aby uzyskać szpilki" lub cokolwiek innego. Ale to już inna historia ...;)

+0

To jest świetna odpowiedź. Przeczytałem dokumentację, ale domyślam się, że zostałem rzucony przez projekt, który brzmiał zgodnie z odplamianiem komórek tabeli. W przypadku komórek tabeli wygląda na to, że ograniczają one rozmiar kolejki, a następnie zaczynają zwalniać komórki tabeli (nie sprawdziłem jednak z debuggerem). To dziwne, że dequeing na mapie nie jest zgodny z tym. Zastanawiam się, dlaczego, gdy logika utrzymywania listy markerów znajdujących się wewnątrz i na zewnątrz bieżącego regionu już istnieje w klasie, programista powinien ją skopiować, aby uzyskać jakiekolwiek rzeczywiste oszczędności w pamięci. Dzięki!! – jmans

+0

Hum, tak, masz rację, to dziwne, ponieważ nazwa jest naprawdę podobna do tej dla UITableView i jak powiedziałeś, słowo "poza ekranem" pozwala użytkownikowi myśleć, że powinno działać jak UITableView. I masz rację, myślę, że jeśli tworzysz widok tabeli z rozmiarem sekcji 10000, nigdy nie otrzymasz 10000 UITableViewCellView utworzonego, ponieważ większość z nich jest ponownie wykorzystywana. dalszy pomysł: kiedy ustawiasz adnotacje w swoim kodzie? Czy jesteś w 100% pewien, że zostanie wywołany po ustawieniu wartości regionu? – yonel

+0

Nie jestem w 100% pewny, ale nie będę miał szansy zadzwonić z moim kodem ponownie do czwartku. Przyjrzę się wtedy jeszcze raz, mając na uwadze twoją radę i dam ci znać, co się stanie. – jmans

0

Nie wiem, czy to pomoże, ale wspomniane problemy z pamięcią spowodowane obciążeniem ~ 60 obiektów. Czy istnieje sposób warunkowego ładowania każdego obiektu w oparciu o bieżące centrum regionu mapy i bieżący obszar regionu mapy?

// :)

+0

Cóż, najlepiej to powinien zrobić dequeueReusableAnnotationViewWithIdentifier, pomyślałem. Myślę, że mogłem to zrobić od zera i zarządzać wieloma lokalizacjami, a za każdym razem, gdy użytkownik przybliża lub przybliża, zdobądź nowy obszar mapy, usuń odpowiednie regiony, a następnie dodaj nowe. – jmans