1

我正在尝试使用无限量的注释填充 MKMapView,这些注释在用户滚动地图时可以查看。显然,用户必须放大到足够远才能显示视图,因为如果不是这样的话,应用程序处理的太多了,一次只能显示大约 20 个。

我有一个包含大约 100 个对象的数组,我需要在整个地图的随机位置随机重复这些对象。这些是在运行时使用 MKMapView 的 visibleMapRect 属性创建的,仅创建必要的。我还实现了一个缓存字典,以防止重新创建以前创建的对象。这是我简化的当前代码:

@property (nonatomic, strong) NSArray *mapObjects; //Contains 100 objects to be repeated
@property (nonatomic, strong) NSMutableDictionary *cache; //Cache already created mapObjects

//Constants used
int const MapDensity  = 5000.0; //Density of annotations
int const MapZoomMax  = 30000.0; //Max zoom level to show annotations

- (void)loadLocations {
    MKMapRect rect = [mapView visibleMapRect];

    if (rect.size.width > MapZoomMax) {
    [self performSelectorOnMainThread:@selector(removeAllAnnotations) withObject:nil waitUntilDone:NO];
        return;
    }

    rect.origin.x = MapDensity*floor(rect.origin.x/MapDensity);
    rect.origin.y = MapDensity*floor(rect.origin.y/MapDensity);

    MKMapPoint pointLocation = rect.origin;
    NSMutableArray *locationsArray = [NSMutableArray array];

    while (pointLocation.y < rect.origin.y+rect.size.height) {
        while (pointLocation.x < rect.origin.x+rect.size.width) {
            int cacheKey = pointLocation.x*pointLocation.y;
            if (![self.cache objectForKey:[NSNumber numberWithInt:cacheKey]]) {

                //Adjust for randomness
                MKMapPoint pointLocationAdjusted = pointLocation;
                pointLocationAdjusted.x += arc4random()%MapDensity;
                pointLocationAdjusted.y += arc4random()%MapDensity;

                //Create annotation
                GLAnnotation *annotation = [[GLAnnotation alloc] init];
                [annotation setCoordinate:MKCoordinateForMapPoint(pointLocationAdjusted)];
                [annotation setMapObject:[self.mapObjects objectAtIndex:(arc4random()%[mapObjects count])]];
                [locationsArray addObject:annotation];

                [self.cache setObject:annotation forKey:[NSNumber numberWithInt:cacheKey]];
            } else {
                [locationsArray addObject:[self.cache objectForKey:[NSNumber numberWithInt:cacheKey]]];
            }
            pointLocation.x += MapDensity; //Go to next X
        }
        pointLocation.x = rect.origin.x; //Restart X
        pointLocation.y += MapDensity; //Go to next Y
    }

    [self performSelectorOnMainThread:@selector(addAnnotations:) withObject:locationsArray waitUntilDone:NO];
}

- (void)addAnnotations:(NSArray *)annotations {
    NSMutableArray *newAnnotations = [NSMutableArray array];
    for (id annotation in annotations) {
        if (![mapView.annotations containsObject:annotation]) {
            [mapView addObject:annotation];
        }
    }
    [mapView addAnnotations:newAnnotations];
}

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
    [self performSelectorInBackground:@selector(loadLocations) withObject:nil];
}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
    if([annotation isKindOfClass:[GLAnnotation class]]){
        static NSString *annotationIdentifier = @"AnnotationIdentifier";

        MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
        if(!annotationView){
            annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
            annotationView.canShowCallout = YES;
        }

        annotationView.image = [(GLAnnotation *)annotation picture];
        return annotationView;
    }
    return nil;
}

该代码似乎大部分时间都可以工作,但有时会导致地图滚动滞后(我试图解决在后台线程中运行它的问题)并且通常会使应用程序崩溃,这似乎是由内存问题引起的(我试图修复使用缓存)。不输出任何错误消息,除了:EXC_BAD_ACCESS。如果有人能告诉我如何正确管理这么多的注释,我将不胜感激。

4

2 回答 2

1

我认为您可能会产生比您需要的多 25,000,000 个项目。但是请检查我的数学。您正在为从 rect.origin 开始并按 MapDensity 递增的每个坐标对创建一个注释。所以每个 5000x5000 块有一个对象。第一个被缓存(0,0)。但是,如果地图视图仅更改了一个地图点,您将拥有一个全新的对象,用于 (0,1) 和以下 5000x5000 块。也许您应该将起点转移到下一个最低的 5000 地图点并从那里增加。这样,您将一直重复使用相同的对象,直到您的起点离开 5000x5000 块。

此外,它们为您的缓存散列会导致冲突。(1,12), (2,6), (3,4), (4,3), (6,2), (12,1), (-1,-12), (-2,-6 ) 等等等等,都散列到相同的值。由于键可以是字符串,请尝试 [NSString stringWithFormat:@"%d_%d",x,y] 代替。

于 2012-08-27T09:45:20.167 回答
0

将它们缓存(到磁盘),由地图图块地址键入。请参阅: http: //www.codeproject.com/Articles/14793/How-Google-Map-Works

于 2012-08-27T08:27:33.970 回答