I'm plotting over 500 points on a map using mapkit. Zooming is a little jittery compared to t开发者_Go百科he native google map app. I've discovered what is causing the slowness. I'm adding custom annotations so that I can later add different pin colors and buttons for detail views:
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(AddressNote *) annotation {
MKPinAnnotationView *annView=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"currentlocation"];
annView.pinColor = MKPinAnnotationColorGreen;
annView.animatesDrop=TRUE;
annView.canShowCallout = YES;
annView.calloutOffset = CGPointMake(-5, 5);
return annView;
}
If I comment out the above code, everything works fine. Very smooth with zooming in/out. Should I be adding annotations differently to boost performance?
500 annotations is probably too many, but not so many that the performance suffers when you are only viewing some of them. However, you should be using dequeueing with your annotations to improve performance
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *view = nil;
if (annotation != mapView.userLocation) {
view = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"identifier"];
if (nil == view) {
view = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"identifier"] autorelease];
}
[view setPinColor:MKPinAnnotationColorGreen];
[view setCanShowCallout:YES];
[view setAnimatesDrop:NO];
}
else {
// Do something with the user location view
}
return view;
}
Also, with 500 pins, the drop animation takes a long time to finish. You should turn that off with [view setAnimatesDrop:NO]
I wrote an iPhone app for a client and we included a store locator for one of their store brands. It includes 501 locations and while the animation can be a bit jerky when you are zoomed out to view the entire United States, it's perfectly fine zoomed in to the state level, where only a handful of pins are visible.
The keys:
- Zoom the user into their current location before you add your annotations.
- Reuse annotation views using
dequeueReusableAnnotationViewWithIdentifier:
.
To achieve the first point, you need to turn on location updates and set a flag when you receive the first one. Animate the map to that location using a region span that makes sense for your app, then in mapView:regionDidChangeAnimated:
, check to see if you still need to add your annotations and that the current location has been updated before you call addAnnotation:
.
If you can't or don't want to zoom in to the user's location, can you filter the annotations shown at the highest level and only add additional annotations as the user zooms in?
By the way, I believe you have a memory leak in your code as posted above. Even if you don't want to use the dequeuing mechanism, the view you return from mapView:viewForAnnotation:
should be autoreleased.
I think St3fan is correct. In theory you can just keep adding annotations to the map and let the view handle display of them, but the reality is that it's better if you keep the count down a bit, 500 on screen at once would be way too many to see anyway.
However there is one more step to try - make sure all of the annotation views have opaque set to YES like so:
annView.opaque = YES;
It sounds to me that adding 500 map points to a section of a map the size of the iPhone screen makes no sense. There is no way you can visualize that or even click on the right annotation.
Can't you look at the zoom level and center of the map and then decide to only add a subset of annotations to the map?
I think I've seen other apps do this too.
If you are not removing annotations not seen by user from view, that is one thing to do by means of MKMapViewDelegate
.
If performance is degrading when user zoom-out to country level you may want to present aggregated info on zoom levels > some const value, e.g. instead of 30 annotations within 10 square miles show single annotation like [30 something]
.
精彩评论