优化MKMapView代码 – 大量注释

我的应用程序中有一个模态视图,显示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 ) 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. // eg self.myOutlet = nil; } 

您可以在这里进行两项最大的速度提升:

  • 实现注释视图重用(现在它每次需要显示注释时都会创建一个新视图,即使同一个视图再次进入视图。
  • 更改UniqueID的设置方式。 为了设置它,代码当前在每次创建注释视图时循环遍历所有注释(这可能在地图视图被缩放或滚动时发生 – 而不仅仅是初始时间)。

首先,不是在viewForAnnotation方法中搜索UniqueID并使用按钮标记来传递注释标识符, 而是将UniqueID作为属性添加到自定义注记类 MyLocation并在addPins添加注释本身时设置属性:

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

您还可以将uniqueID作为参数添加到initWithName方法,而不是单独分配属性。

接下来,要实现注释视图重用, viewForAnnotation方法应如下所示:

 - (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id ) 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... } 

在所有这些更改之后,只有注释的初始加载将占用大部分时间。 如果这仍然是一个问题,一种解决方案是仅添加在当前显示的区域中可见的注释,并在用户更改可见区域时添加/删除注释。

我完全赞同安娜。 但考虑到800 AnnotationViews同时会导致极端滞后的界面。 因此,如果您的地图应提供滚动或缩放等用户交互,则最好实现注释视图的某种聚类。