2011-10-27 18 views
8

Mam widok modalny w mojej aplikacji, który wyświetla UIMapView. Następnie dodaję dużą liczbę adnotacji (ponad 800) do tego widoku mapy (kod poniżej).Optymalizowanie kodu dla MKMapView - duża liczba adnotacji

Problem polega na tym, że użytkownik musi odczekać około minuty, gdy wszystkie piny się wczytują. Również aplikacja staje się powolna, gdy wszystkie 800 pinów są na mapie.

Czy ktoś może zasugerować, w jaki sposób mogę poprawić poniższy kod?

Dziękuję.

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

Odpowiedz

10

Dwa największe ulepszenia prędkości można dokonać tutaj:

  • Wdrożenie widoku opisu ponownego wykorzystania (teraz tworzy nowy widok za każdym razem musi pokazać adnotację nawet jeśli ten sam Pojawia się ponownie
  • Zmiana ustawienia UniqueID. Aby go ustawić, kod przechodzi obecnie przez wszystkie adnotacje za każdym razem, gdy tworzy widok adnotacji (co może się zdarzyć za każdym razem, gdy widok mapy jest powiększany lub przewijany- -nie tylko początkowy czas).

Po pierwsze, zamiast szukać dla UniqueID w metodzie viewForAnnotation i przy użyciu znacznika przycisk, aby przekazać identyfikator adnotacji, dodać UniqueID jako właściwość do niestandardowej klasy adnotacjiMyLocation i ustawić właściwość podczas dodawania adnotacji sam w addPins:

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

można również dodać uniqueID jako parametr do metody initWithName zamiast przypisywania właściwości oddzielnie.


Następnie wdrożyć adnotacji widoku ponownego wykorzystania, metoda viewForAnnotation powinna wyglądać następująco:

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


Wreszcie w odpowiedzi na przycisk prasy i dowiedzieć się, które UniqueID aby zobaczyć szczegóły o, realizację sposobu calloutAccessoryControlTapped z przekazanym:

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


Po tych wszystkich zmianach tylko początkowe ładowanie adnotacji będzie zajmować większość czasu. Jeśli to nadal stanowi problem, jednym z rozwiązań jest dodawanie adnotacji, które byłyby widoczne w aktualnie wyświetlanym regionie oraz dodawanie/usuwanie adnotacji, gdy użytkownik zmienia widoczny obszar.

4

Całkowicie zgadzam się z Anną. Ale zastanów się, że 800 AdnotationViews w tym samym czasie spowoduje ekstremalnie opóźniony interfejs. Jeśli więc mapa powinna zapewniać interakcję z użytkownikiem, np. Przewijanie lub powiększanie, lepiej zaimplementuj klastrowanie widoków adnotacji.

Powiązane problemy