Оптимизация кода для MKMapView - большое количество аннотаций - PullRequest
8 голосов
/ 27 октября 2011

У меня есть модальное представление в моем приложении, которое отображает UIMapView.Затем я добавляю большое количество аннотаций (более 800) к этому виду карты (код ниже).

Проблема в том, что пользователь вынужден ждать около минуты, пока загружаются все выводы.Кроме того, приложение становится вялым, когда все 800 пинов находятся на карте.

Кто-нибудь может подсказать, как я могу улучшить свой код ниже?

Спасибо.

#import "MapView.h"
#import "MapPlaceObject.h"


@implementation MapView
@synthesize mapViewLink, mapLocations, detail, failedLoad;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
    // Custom initialization
}
return self;
}

-(void)addPins
{

for (MapPlaceObject * info in mapLocations) {


    double latitude = info.longitude;
    double longitude = info.latitude;

    NSString * name = info.name;
    NSString * addressline = info.addressOne;
    NSString * postcode = info.postCode;

    NSString * addresscomma = [addressline stringByAppendingString:@", "];
    NSString * address = [addresscomma stringByAppendingString:postcode];

    CLLocationCoordinate2D coordinate;
    coordinate.latitude = latitude;
    coordinate.longitude = longitude;
    MyLocation *annotation = [[[MyLocation alloc] initWithName:name address:address coordinate:coordinate] autorelease];


    [mapViewLink addAnnotation:annotation];

}
}

- (void)showLinks : (id)sender {


if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    detail = [[DetailViewController alloc] initWithNibName:@"DetailViewController-iPad" bundle:nil];
} 

else if (!detail) {

    NSLog(@"Detail is None");

    detail = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil]; 

}

int uniqueID = ((UIButton *)sender).tag;

//PlaceObject *info = [mapLocations objectAtIndex:uniqueID];

detail.UniqueID = uniqueID;
detail.hidesBottomBarWhenPushed = YES;

[self.navigationController pushViewController:detail animated:YES];

self.detail = nil;

[detail release];

}

- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation{

if (annotation == mapView.userLocation){
    return nil; //default to blue dot
}    

MKPinAnnotationView *annView=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"currentloc"];
annView.pinColor = MKPinAnnotationColorRed;

nameSaved = annotation.title;

for (PlaceObject * info in mapLocations) {

    if (info.name == nameSaved) {

        saveID = info.UniqueID;

    }
}

UIButton *advertButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
advertButton.frame = CGRectMake(0, 0, 23, 23);
advertButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
advertButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;

[advertButton addTarget:self action:@selector(showLinks:) forControlEvents:UIControlEventTouchUpInside];

advertButton.tag = saveID;

annView.rightCalloutAccessoryView = advertButton;

annView.animatesDrop=TRUE;
annView.canShowCallout = YES;
annView.calloutOffset = CGPointMake(-5, 5);
return annView;

}

- (void)dealloc
{
[mapViewLink release];
[mapLocations release];
[detail release];
self.failedLoad = nil;
[failedLoad release];
[super dealloc];
}

- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

- (void)viewWillAppear:(BOOL)animated {

if (firstTime) {

    CLLocationCoordinate2D zoomLocation;

    zoomLocation.latitude = 51.50801;
    zoomLocation.longitude = -0.12789;

    MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 15*METERS_PER_MILE, 15*METERS_PER_MILE);

    MKCoordinateRegion adjustedRegion = [mapViewLink regionThatFits:viewRegion];                

    [mapViewLink setRegion:adjustedRegion animated:YES];  

    firstTime = NO;

}    
}

- (void)viewDidLoad
{
[super viewDidLoad];

firstTime = YES;

failedLoad = [[NSMutableArray alloc]init];

self.mapLocations = [BluePlaqueDatabase database].mapInfo;

[self addPins];
}

- (void)viewDidUnload
{
[mapViewLink release];
mapViewLink = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}

Ответы [ 2 ]

10 голосов
/ 28 октября 2011

Два самых больших улучшения скорости, которые вы можете сделать здесь:

  • Реализация представления аннотации для повторного использования (сейчас он создает новый вид каждый раз, когда ему нужно отобразить аннотацию, даже если тот же самый вид снова появляется.
  • Изменить способ установки UniqueID. Чтобы установить его, код в настоящее время просматривает все аннотации каждый раз, когда создает представление аннотации (что может произойти всякий раз, когда представление карты масштабируется или прокручивается, а не только в начальный момент времени).

Во-первых, вместо поиска UniqueID в методе viewForAnnotation и использования тега кнопки для передачи идентификатора аннотации, добавьте UniqueID в качестве свойства к вашему пользовательскому классу аннотаций MyLocation и установите свойство при добавлении самой аннотации в addPins:

annotation.uniqueID = info.UniqueID;  // <-- give id to annotation itself
[mapViewLink addAnnotation:annotation];     

Вы также можете добавить uniqueID в качестве параметра к методу initWithName вместо того, чтобы назначать свойство отдельно.


Далее, чтобы реализовать повторное использование представления аннотации, метод viewForAnnotation должен выглядеть следующим образом:

- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation{

    if (annotation == mapView.userLocation){
        return nil; //default to blue dot
    }    

    NSString *reuseId = @"StandardPin";
    MKPinAnnotationView *annView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
    if (annView == nil)
    {
        annView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId] autorelease];

        annView.pinColor = MKPinAnnotationColorRed;
        annView.animatesDrop = YES;
        annView.canShowCallout = YES;
        annView.calloutOffset = CGPointMake(-5, 5);

        UIButton *advertButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        advertButton.frame = CGRectMake(0, 0, 23, 23);
        advertButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
        advertButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;

        annView.rightCalloutAccessoryView = advertButton;
    }
    else
    {
        //update the annotation property if view is being re-used...
        annView.annotation = annotation;
    }

    return annView;
}


Наконец, чтобы отреагировать на нажатие кнопки и выяснить, для какого UniqueID показывать подробности, реализуйте метод делегата calloutAccessoryControlTapped:

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view 
            calloutAccessoryControlTapped:(UIControl *)control
{
    MyLocation *myLoc = (MyLocation *)view.annotation;

    int uniqueID = myLoc.uniqueID;

    NSLog(@"calloutAccessoryControlTapped, uid = %d", uniqueID);

    //create, init, and show the detail view controller here...
}


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

4 голосов
/ 28 октября 2011

Я полностью согласен с Анной. Но учтите, что 800 AnnotationViews одновременно приведут к крайне медленному интерфейсу. Поэтому, если ваша карта должна обеспечивать взаимодействие с пользователем, такое как прокрутка или масштабирование, вам лучше реализовать некую кластеризацию ваших аннотаций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...