2012-08-27 27 views
0

我想填充一個MKMapView,當用戶滾動瀏覽地圖時可以看到無數的註釋。很明顯,用戶必須放大到足以讓視圖出現,因爲如果不是,應用程序處理太多,每次只顯示約20個視圖。帶有無限的隨機註釋的MKMapView

我有一個約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。如果有人能告訴我如何正確管理這些註釋,我將非常感激。

回答

0

我認爲您可能會生成超過您需要的25,000,000個項目。但請檢查我的數學。您正在從rect.origin開始爲每個座標對創建一個註釋,並通過MapDensity遞增。所以每個5000x5000塊都有一個對象。第一個被緩存(0,0)。但是,如果地圖視圖僅由一個mappoint更改,則會爲(0,1)和隨後的5000x5000塊創建一個全新的對象。也許你應該把你的出發點轉移到下一個最低的5000點,並從那裏增加。這樣你就可以重複使用同一個對象,直到你的起點離開5000x5000塊。

此外,它們爲您的緩存散列會導致衝突。 (1,12),(2,6),(3,4),(4,3),(6,2),(12,1),( - 1,-12),( - )等等,都散列到相同的值。由於密鑰可以是字符串,請嘗試[NSString stringWithFormat:@「%d_%d」,x,y]。

+0

是的,你是對的緩存錯誤。這部分似乎工作正常,所以我沒有注意到,但如果用戶在一些敏感的地方,它很容易被注意到。謝謝! – gabriellanata

+0

在第一部分中,我添加了下面的代碼來移動起點,但我仍然得到了很多內存錯誤: 'rect.origin.x - = MapDensity * floor(rect.origin.x/MapDensity);' 'rect.origin.y - = MapDensity * floor(rect.origin.y/MapDensity);' – gabriellanata

+0

看起來你正在穿過你的流。 regionDidChangeAnimated調用發生在ui線程上,然後在後臺線程上loadLocations,但它將刪除註釋並將其添加到mapview,因此它應該在主線程/ ui線程上。什麼是locationsMap? – Craig