Memory management 具有无限随机注释的MKMapView
我试图用无限量的注释填充MKMapView,当用户在地图上滚动时可以看到这些注释。显然,用户必须被放大到足以显示视图的程度,因为如果不放大,应用程序将无法处理,一次只能显示大约20个视图 我有一个大约100个对象的数组,我需要在地图上的任意位置随机重复。这些是在运行时使用MKMapView的visibleMapRect属性创建的,以仅创建必要的。我还实现了一个缓存字典,以防止重新创建以前创建的对象。以下是我当前的简化代码:Memory management 具有无限随机注释的MKMapView,memory-management,mkmapview,mkannotation,mapkit,Memory Management,Mkmapview,Mkannotation,Mapkit,我试图用无限量的注释填充MKMapView,当用户在地图上滚动时可以看到这些注释。显然,用户必须被放大到足以显示视图的程度,因为如果不放大,应用程序将无法处理,一次只能显示大约20个视图 我有一个大约100个对象的数组,我需要在地图上的任意位置随机重复。这些是在运行时使用MKMapView的visibleMapRect属性创建的,以仅创建必要的。我还实现了一个缓存字典,以防止重新创建以前创建的对象。以下是我当前的简化代码: @property (nonatomic, strong) NSArra
@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;
}
@property(非原子,强)NSArray*mapObjects//包含100个要重复的对象
@属性(非原子,强)NSMutableDictionary*缓存//缓存已创建的映射对象
//使用的常数
int const MapDensity=5000.0//注释密度
int const MapZoomMax=30000.0//显示注释的最大缩放级别
-(无效)装载位置{
MKMapRect rect=[mapView visibleMapRect];
如果(rect.size.width>MapZoomMax){
[self-performSelectorOnMainThread:@selector(RemoveAllNotations),对象:nil waitUntilDone:NO];
返回;
}
rect.origin.x=MapDensity*floor(rect.origin.x/MapDensity);
rect.origin.y=MapDensity*floor(rect.origin.y/MapDensity);
MKMapPoint pointLocation=rect.origin;
NSMutableArray*位置数组=[NSMutableArray];
while(pointLocation.y
代码似乎大部分时间都在工作,但有时会导致地图滚动延迟(我尝试在后台线程中运行它),并且通常会导致应用程序崩溃,这似乎是由内存问题(我尝试使用缓存修复)引起的。不输出任何错误消息,除非:EXC\u BAD\u ACCESS。如果有人能告诉我如何正确管理这么多的注释,我将不胜感激。将它们缓存(到磁盘),并按地图块地址键入。请参阅:我认为您可能会生成超过需要的25000000个项目。但是请检查我的数学。您将从rect.origin开始为每个坐标对创建一个注释,并按MapDensity递增。因此,每个5000x5000块对应一个对象。正在缓存的第一个(0,0)。但是,如果地图视图只更改了一个贴图点,则(0,1)将有一个全新的对象和以下5000x5000块。也许你应该把你的起点移到下一个最低点,然后从那里开始递增。这样,您就可以一直重用同一对象,直到您的起点离开5000x5000块
此外,它们对缓存进行哈希运算会导致冲突。(1,12),(2,6),(3,4),(4,3),(6,2),(12,1),(-1,-12),(-2,-6)等,所有哈希值都相同。由于密钥可以是字符串,请尝试[NSString stringWithFormat:@“%d_%d”,x,y]替换。是的,关于缓存错误,您是对的。这部分似乎工作正常,所以我没有注意到,但如果用户在一些敏感的位置,它很容易被注意到。非常感谢。在第一部分中,我添加了以下代码来改变起点,但仍然会出现很多内存错误:
rect.origin.x-=MapDensity*floor(rect.origin.x/MapDensity)代码>rect.origin.y-=MapDensity*floor(rect.origin.y/MapDensity)代码>看起来你正在穿越河流。regionDidChangeAnimated调用发生在ui线程上,然后在后台加载位置