2011-10-03 13 views
1

私はジオコーディングで位置情報を取得し、Googleマップビューに地図ピンを追加するために以下のコードを使用しています。このコードでは、Forループを使用してデータベースの各場所を循環します。問題は、実行時に場所の約50%の場所情報をコードが返さないことです。これらの失敗した項目は、以下のコードに従ってfailedLoad配列に保存されます。Googleジオコーディングを使用してForループ - 高いエラー率 - iPhone

これはどのような理由が考えられますか?また、これらの失敗したアイテムは "failedLoad"配列に保存されるので、この配列を使用して欠落しているピンをロードする方法はありますか?

EDIT

失敗したアイテムは、私があまりにも早く項目を提出していますことを意味620エラーに起因するものです。コードに遅延を追加するにはどうすればよいですか?

ありがとうございます!

-(void)displayPlaces { 


for (PlaceObject *info in mapLocations) { 

     // GET ANNOTATION INFOS 
     NSString * addressOne = info.addressOne; 
     NSString * name = info.name; 
     NSString * postCode = info.postCode; 

     NSString * addressTwo = [addressOne stringByAppendingString:@",London,"]; 
     NSString * address = [addressTwo stringByAppendingString:postCode]; 

     NSString* urlString = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 
     NSURL* url = [NSURL URLWithString:urlString]; 
     NSURLRequest* req = [NSURLRequest requestWithURL:url]; 

     OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req]; 
     [loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) { 
      NSString* locationString = loader.receivedString; 
      NSArray *listItems = [locationString componentsSeparatedByString:@","]; 

     double latitude = 0.0; 
     double longitude = 0.0; 

     if([listItems count] >= 4 && [[listItems objectAtIndex:0] isEqualToString:@"200"]) { 
      latitude = [[listItems objectAtIndex:2] doubleValue]; 
      longitude = [[listItems objectAtIndex:3] doubleValue]; 

     } 

     else { 

      NSLog(@"Error %@",name); 
      [failedLoad addObject : info]; 

     } 


     CLLocationCoordinate2D coordinate; 
     coordinate.latitude = latitude; 
     coordinate.longitude = longitude; 
     MyLocation *annotation = [[[MyLocation alloc] initWithName:name address:address coordinate:coordinate] autorelease]; 

     [mapViewLink addAnnotation:annotation]; 

     } errorHandler:^(NSError *error) { 
      NSLog(@"Error while downloading %@: %@",url,error); 
     }]; 

} 


} 
+0

Google APIにはさまざまなクエリレートの制限があります。 1秒あたり最大10件のリクエスト。 APIを使用する予定がある場合は、実際にこのすべてをRTFMする必要があります。 –

+1

場所が読み込まれない場合は、返された文字列をログに記録しないでください。なぜそれが失敗するのかはすぐに分かります。 – JeremyP

+0

ありがとうございます - 私が理解している620エラーは、私が提出しているレートによるものです。私はどのようにしてコードを遅らせるのでしょうか? – GuybrushThreepwood

答えて

2

代わりのforループを使用して、同時にすべてのリクエストを送信、あなたはおそらく(5または5?)それらを次々に送るべき

ここでそれを行うための一つの方法ですは、(実際のコードでテストされていません、私は行くいくつかのタイプミスを有することができるようちょうど型付け):もちろん

// In the instance variables, have: 
@property(retain) NSMutableSet* mapLocationsToGeocode; 

// When you want to decode, use: 
self.mapLocationsToGeocode = [NSMutableSet setWitharray:mapLocations]; 
// (Or add to the existing NSSet if you have one and add Places using multple passes) 
[self popLocationAndGeocode]; 

-(void)popLocationAndGeocode 
{ 
    // Pop any location from the set 
    PlaceObject* onePlace = [mapLocationsToGeocode anyObject]; 

    // Build the URL given the PlaceObject 
    NSString* address = [NSString stringWithFormat:@"%@,London,%@",info.addressOne,info.postCode]; 
    NSString* name = info.name; 

    NSString* urlString = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 
    NSURLRequest* req = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]; 

    // Remove it so it won't be poped again 
    [mapLocationsToGeocode removeObject:onePlace]; 

    // Send the request here to decode the PlaceObject 
    OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req]; 
    [loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) { 
    NSString* locationString = loader.receivedString; 
    NSArray* listItems = [locationString componentsSeparatedByString:@","]; 
    ... 

    if([listItems count] >= 4 && [[listItems objectAtIndex:0] isEqualToString:@"200"]) { 
     // Process with latitude and longitude, add your MKAnnotation, etc 
    } else { 
     NSLog(@"Error %@",name); 
     [failedPlaces addObject:onePlace]; 
    } 
    ... 

    // Schedule the next decoding request (1) 
    if ([mapLocationsToGeocode count]) [self performSelector:@selector(popLocationAndGeocode) withObject:nil afterDelay:0.1]; 
    } errorHandler:^(NSError *error) { 
     NSLog(@"Error while downloading %@: %@",url,error); 
     [failedPlaces addObject:onePlace]; 

     // Schedule the next decoding request anyway (1) 
     if ([mapLocationsToGeocode count]) [self performSelector:@selector(popLocationAndGeocode) withObject:nil afterDelay:0.1]; 
    }]; 

    // Schedule the next decoding request (2) -- solution 2 
    // if ([mapLocationsToGeocode count]) [self performSelector:@selector(popLocationAndGeocode) withObject:nil afterDelay:1.0]; // wait one sec before sending next request 
} 

、行われたときに戻ってnilにプロパティを設定(またはdeallocで)解放することを忘れてはいけません想い出。

(1)の場合、完了ブロックとエラーブロックの両方でperformSelector:withObject:afterDelayを呼び出します。そのため、次の要求/デコード処理は最初の処理が完了した後にのみ呼び出されます。このようにして、あなたのリクエストはいくらかシリアル化されます。

startRequestWithCompletion:...メソッドの直後にperformSelector:withObject:afterDelayがコールされるので、最初のリクエストが終了して次のリクエストがポップされるのを待ちません。あなたは、これが唯一の解決策ではないことをGoogleAPIレート制限に


ノートに到達しないだろうたくさんの他の可能性があるように、しかし、あなたは十分な長さ(たぶん)お待ちしております。 1つは、NSOperationQueueを使用してキューに要求を1つずつキューイングし、それに依存関係を追加するか、GCDシリアルキューで要求の送信プロセスをスケジュールすることです(実際にはGCDを使用しないように言われたことはわかります)あなたの要求を送信しますが、まだ適用されますが、GCD +同期要求は使用しませんが、GFCを使用して[OHURLLoader startRequestWithCompletion:...]をメインスレッド上で呼び出すブロックをキューに入れることができます。 RunLoop)

+0

ありがとうございます - うまくいくようです。しかし、ピンの追加が終わったらアプリがクラッシュします。 mapLocationsToGeocode配列が空になったらセレクター/タイマーを停止するにはどうすればよいですか? – GuybrushThreepwood

+0

OKは次のように修正されました:[self performSelector:@selector(popLocationAndGeocode)withObject:nil afterDelay:0.15]; int x = [mapLocationsToGeocode count]; if(x <= 1){ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(popLocationAndGeocode)オブジェクト:なし]; } – GuybrushThreepwood

+0

「performSelector」リクエストをスケジューリングするのではなく、直後にキャンセルするのではなく、 'if([mapLocationsToGeocode count])[self performSelector:]を使用してください。 withObject:nil afterDelay:...] ' – AliSoftware

関連する問題