Обработка большого количества аннотаций MKMapView

У меня есть представление карты с большим количеством аннотаций (3000+), когда пользователь масштабируется до разумного уровня, все хорошо и быстро.

Хотя, когда пользователь масштабируется и появляется большой quanitiy аннотаций, происходит много замедления из-за того, что сразу отображается количество аннотаций. Каков наилучший способ справиться с этим?

Текущее решение, которое я использую:

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

Отлично работает, хотя из-за большого размера цикла это приводит к значительному замедлению при масштабировании и выводе и прокрутке. Кажется, я не думаю о более эффективном способе справиться с этим, есть ли способ только прокрутить отображаемые в настоящее время аннотации или что-то по этим линиям, чтобы уменьшить размер цикла?

Ответ 1

Как я понимаю ваш код, вы скрываете все представления аннотаций, если mapView увеличен более чем на определенное заданное значение.

Мне кажется, что было бы лучше, чем следующее:

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

С приведенным выше, в большинстве случаев единственное, что делает этот код, это пара проверок.

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

Ответ 2

Я бы предложил пару вещей. Один, посмотрите на метод annotationsInMapRect:. Согласно документам, в нем говорится:

Этот метод предлагает быстрый способ извлечения объектов аннотации в определенной части карты. Этот метод намного быстрее, чем выполнить линейный поиск объектов в свойстве аннотаций.

Два, посмотрите dequeueReusableAnnotationViewWithIdentifier:. Согласно документам снова, в нем говорится:

По соображениям производительности вы обычно должны повторно использовать объекты MKAnnotationView в своих представлениях на карте. Поскольку представления аннотаций перемещаются за кадром, представление карты перемещает их в очередь повторного использования внутри организации. По мере того, как новые аннотации перемещаются на экране, а вашему коду предлагается предоставить соответствующий аннотационный вид, вы всегда должны пытаться удалить существующий вид перед созданием нового. Dequeueing экономит время и память во время критически важных операций, таких как прокрутка.

Наконец, пара мыслей. Вместо того, чтобы делать эти изменения каждый раз, когда вызывается метод - (void)mapView:(MKMapView *)_mapView regionDidChangeAnimated:(BOOL)animated, как насчет того, чтобы делать это в соответствии с каким-либо другим правилом (например, после запуска таймера [убедитесь, что reset таймер при каждом вызове])? Другое дело: как объединить аннотации, которые очень близки друг к другу? Скажем, вы уменьшились до того места, где Род-Айленд выглядит очень маленьким, может быть, всего в десятке пикселей в ширину, и у вас есть 100 очков в Род-Айленде - вы должны просто отобразить один вывод.

Надеюсь, это поможет!

Ответ 3

В итоге я группировал свои аннотации в кластерах, используя OCMapView. Его бесплатный и очень простой в использовании в существующий код.

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

Я знаю, что это старый вопрос, но это отличный вариант для всех, кто пытается сделать то же самое.