MKMapView загружает все представления аннотаций одновременно (включая те, которые находятся вне текущего прямоугольника) - PullRequest
13 голосов
/ 12 августа 2009

UPDATE

Похоже, эта проблема была тихо исправлена ​​в iOS 4.3. До этого момента расстояние, которое считалось «достаточно большим» для повторного использования аннотации, казалось, составляло сотни миль, даже при очень близком увеличении. Когда я создаю свое приложение с помощью iOS 4.3 SDK, аннотации перерабатываются на основе более разумных ограничений.


Кто-нибудь еще сталкивался с этой проблемой? Вот код:

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

...

Как только отображается вид, я получаю

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

и так далее, для каждой аннотации (~ 60), которую я добавил. Карта (правильно) отображает только две аннотации в текущем прямоугольнике. Я устанавливаю регион в 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];

Запись журнала для заданного региона выводится на консоль, прежде чем запрашиваются какие-либо аннотации.

Проблема здесь в том, что, поскольку все аннотации запрашиваются одновременно, [mapView dequeueReusableAnnotationViewWithIdentifier] ничего не делает, поскольку для каждой аннотации на карте существуют уникальные MKAnnotationViews. Это приводит к проблемам с памятью для меня.

Одна из возможных проблем заключается в том, что эти аннотации сгруппированы в довольно небольшом пространстве (радиус ~ 1 мили). Хотя карта довольно сильно увеличена в viewDidLoad (разность широты и долготы .001), она по-прежнему загружает все виды аннотаций одновременно.

Спасибо ...

Ответы [ 2 ]

14 голосов
/ 29 марта 2010

То, что вы ожидаете, - это своего рода «отсечение» представлений аннотаций на основе текущей region карты, отображаемой.

Это НЕ способ, которым работает селектор dequeueReusableAnnotationViewWithIdentifier.

Из своей документации: Когда представления аннотаций перемещаются за пределы экрана , представление карты перемещает их в очередь повторного использования с внутренним управлением. Когда новые аннотации перемещаются на экране, и ваш код запрашивается для предоставления соответствующего представления аннотации, вы всегда должны пытаться удалить существующее представление из очереди перед созданием нового.

Таким образом, механизм многократного использования имеет смысл только тогда, когда вы вызываете последовательность вроде: //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];

В вашем случае, я бы применил обрезку (для отображения только аннотации для текущей отображаемой области):

  • Добавьте делегата в свой mapView и реализуйте метод - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated, чтобы получать информацию об изменении региона
  • переберите все ваши объекты, чтобы найти те, которые соответствуют этой области
  • добавить аннотации к вашей карте только для этих объектов (вы можете реализовать своего рода объединение ранее отображенных аннотаций с новыми или просто перезапустить с нуля, удалить все аннотации и установить новые

Конечно, когда пользователь значительно уменьшает масштаб и область области слишком велика (слишком много выводов для отображения), вам необходимо принять решение: отобразить ли все представления аннотаций (и рискнуть тем, что отображение на карте не дает много информации), или я устанавливаю сообщение пользователю, говорящее «увеличить, чтобы получить булавки» или что-то еще. Но это другая история ...;)

0 голосов
/ 12 октября 2009

Не уверен, поможет ли это, но вы упомянули проблемы с памятью из-за загрузки ~ 60 объектов. Есть ли способ условно загрузить каждый объект на основе текущего центра области карты и текущего диапазона области карты?

//:)

...