使用Google地理编码进行循环-高错误率-iPhone [英] For Loop with Google Geocoding - High Error Rate - iPhone

查看:71
本文介绍了使用Google地理编码进行循环-高错误率-iPhone的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用以下代码通过地址解析获取位置信息,然后将地图图钉添加到Google地图视图中.该代码使用For循环遍历数据库中的每个位置.问题在于,运行时代码无法返回约50%的位置的位置信息.这些失败的项目按照下面的代码保存在failLoad数组中.

I am using the below code to fetch location information via Geocoding and then add a map pin to a Google Map View. The code uses a For loop to cycle through each place in my database. The problem is that the code fails to return location info for about 50% of the places when run. These failed items are saved in the failedLoad array as per the code below.

任何人都可以建议这是为什么吗?另外,由于这些失败的项目保存在"failedLoad"数组中,有没有办法我可以使用该数组来加载所有丢失的引脚?

Can anyone suggest why this is ? Also since these failed items are saved in the "failedLoad" array, is there a way I could use this array to load any missing pins ?

编辑

失败的项目归因于620错误,这意味着我提交项目的速度太快.如何在代码中添加延迟?

The failed items are due to a 620 error which means that I am submitting items too quickly. How can I add a delay into the code ?

谢谢!

-(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);
       }];

 }


}

推荐答案

与其使用for循环并同时发送所有请求,您可能应该一个接一个地发送它们(或5乘5?)

Instead of using a for loop and send all your requests at the same time, you probably should send them one after the other (or 5 by 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
}

当然,不要忘了在完成操作后(或在dealloc中)将属性设置回nil以释放内存.

Of course, dont forget to set the property back to nil when done (or in the dealloc) to release the memory.

在情况(1)中,我在完成和错误块中均调用performSelector:withObject:afterDelay,以便仅在第一个请求/解码过程完成后才调用下一个请求/解码过程.这样,您的请求就会被序列化.

In case (1), I call performSelector:withObject:afterDelay in both the completion and error blocks, so that the next request/decoding process is called only once the first has finished. This way your requests are somewhat serialized.

在情况(2)(注释/禁用)中,我在startRequestWithCompletion:...方法之后立即调用performSelector:withObject:afterDelay,因此它不会等待第一个请求的结束弹出下一个请求.但是,您将等待(希望)足够长的时间,这样您就不会达到GoogleAPI的速率限制

In case (2) (commented/disabled), I call performSelector:withObject:afterDelay right after the startRequestWithCompletion:... method, so it won't wait for the end of the first request to pop the next one. But you will wait (hopefully) long enough so that you won't reach the GoogleAPI rate limit

请注意,这不是唯一的解决方案,还有许多其他可能性.一种是使用NSOperationQueue将请求一个接一个地排队在队列中,并添加对它的依赖关系,或者将请求的发送过程安排在GCD串行队列上(是的,我知道我告诉过您不要使用GCD来实际上发送您的请求,但是仍然适用,仍然不使用GCD +同步请求,但是您可以使用GCD来排队将在主线程上依次调用[OHURLLoader startRequestWithCompletion:...]的块;另一个是请求本身仍由RunLoop在主线程上执行)

Note that this is not the only solution, there are plenty other possibilities. One being to use NSOperationQueue to queue the requests one after the other on a queue and add dependencies to it, or schedule the sending process of the requests on a GCD serial queue (yeah, I know I told you not to use GCD to actually send your requests, but that still apply, still dont use GCD+synchronous requests, but you can use GCD to queue blocks that will call [OHURLLoader startRequestWithCompletion:...] on the main thread one after the other; the request itself still being executed on the main thread by the RunLoop)

这篇关于使用Google地理编码进行循环-高错误率-iPhone的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆