#iphone #objective-c #ios #ipad #mkmapview
#iPhone #objective-c #iOS #iPad #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 <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;
}
Ответ №1:
Два самых больших улучшения скорости, которые вы можете сделать здесь::
- Реализовать повторное использование представления аннотаций (прямо сейчас он создает новое представление каждый раз, когда ему нужно отобразить аннотацию, даже если она снова появляется в поле зрения.
- Измените способ
UniqueID
установки. Чтобы установить его, код в настоящее время перебирает все аннотации каждый раз, когда он создает представление аннотаций (что может произойти в любое время, когда вид карты увеличивается или прокручивается, а не только в начальный раз).
Во-первых, вместо поиска UniqueID
в viewForAnnotation
методе и использования тега button для передачи идентификатора аннотации, добавьте 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...
}
После всех этих изменений большую часть времени будет занимать только начальная загрузка аннотаций. Если это все еще проблема, одним из решений является добавление аннотаций, которые будут видны только в текущей отображаемой области, и добавление / удаление аннотаций по мере изменения пользователем видимой области.
Ответ №2:
Я полностью согласен с Анной. Но учтите, что 800 просмотров аннотаций одновременно приведут к крайне медленному интерфейсу. Поэтому, если ваша карта должна обеспечивать взаимодействие с пользователем, например, прокрутку или масштабирование, вам лучше реализовать некоторую кластеризацию ваших представлений аннотаций.