MKMapView具有无限随机注释

时间:2012-08-27 08:15:38

标签: memory-management mkmapview mkannotation mapkit

我正在尝试使用无限量的注释来填充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。如果有人能告诉我如何正确管理这些数量的注释,我将非常感激。

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

我认为你可能会产生超过你需要的25,000,000件物品。但请检查我的数学。您正在为每个坐标对创建一个注释,从rect.origin开始并通过MapDensity递增。因此每个5000x5000块有一个对象。第一个被缓存(0,0)。但是如果只有一个mappoint改变了地图视图,那么(0,1)和随后的5000x5000块就会有一个全新的对象。也许你应该把你的起点转移到下一个最低的5000 mappoint并从那里增加。这样,您将始终重复使用相同的对象,直到您的起点离开5000x5000块。

此外,他们为您的缓存哈希导致冲突。 (1,12),(2,6),(3,4),(4,3),(6,2),(12,1),( - 1,-12),( - 2, - )等等,都哈希到相同的值。由于键可以是字符串,因此尝试[NSString stringWithFormat:@“%d_%d”,x,y]。