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 ずつ増加する座標ペアごとに 1 つの注釈を作成しています。つまり、5000x5000 ブロックごとに 1 つのオブジェクトです。キャッシュされる最初のもの (0,0)。しかし、マップ ビューが 1 つのマップ ポイントだけ変更された場合、(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 に答える