使用前向地理编码获取iOS中许多地址的纬度和经度时如何添加延迟?

Posted

技术标签:

【中文标题】使用前向地理编码获取iOS中许多地址的纬度和经度时如何添加延迟?【英文标题】:How to add a delay when using forward-geocoding to get Latitude and Longitude for many addresses in iOS? 【发布时间】:2013-01-28 06:48:57 【问题描述】:

我的核心数据中有一些地址,我需要获取它们的纬度和经度。地址的数量约为 150 到 200 个。我在线程 iPhone ios5 CLGeocoder how to geocode a large (200) set of addresses? 中读到 iOS 将您限制为每分钟 50 个地理编码。我需要知道如何在那一分钟内触发 50 个地理编码,然后再触发 50 个,依此类推。执行代码我得到以下错误:

Geocode 失败并出现错误:Error Domain=kCLErrorDomain Code=2 “操作无法完成。(kCLErrorDomain 错误 2.)”

用户 nob1984 在我提到的线程中提出了一个可能的解决方案:

如果您需要一次对所有内容进行地理编码,则需要将地理编码与每个块之间的延迟链接在一起,并在完成之前显示某种忙碌指示符。这可能需要一些时间来处理大量的地理编码。

但我不知道如何使这些延迟正常工作。欢迎任何帮助和建议!谢谢

代码如下:

...
NSArray *arrayOfRoutePoints = fetchedObjects;
[self geolocateGroup:arrayOfRoutePoints];
...

- (void)geolocateGroup:(NSArray *)array 
for (RoutePoint *rp in array) 
    if ([rp.addressLatitude intValue] == 0) 
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_enter(group);

        [self geolocateRoutePoint:rp];

        dispatch_group_leave(group);

        while(dispatch_group_wait(group,DISPATCH_TIME_NOW))
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                     beforeDate:[NSDate dateWithTimeIntervalSinceNow:3.0f]];
        
    
    
     

- (void)geolocateRoutePoint:(RoutePoint *)c 
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
NSString *addressString = [NSString stringWithFormat:@"%@,%@ %@ %@ %@",
                           c.addressName,
                           c.addressNumber,
                           @"SOME CITY",
                           @"SOME STATE",
                           @"SOME COUNTRY"];

[geocoder geocodeAddressString:addressString
             completionHandler:^(NSArray *placemarks, NSError *error) 

                 if (error) 
                     NSLog(@"Geocode failed with error: %@", error);
                     return;
                 

                 if (placemarks && placemarks.count > 0)
                 
                     CLPlacemark *placemark = placemarks[0];

                     CLLocation *location = placemark.location;
                     c.addressLatitude =  [NSNumber numberWithDouble:location.coordinate.latitude];
                     c.addressLongitude = [NSNumber numberWithDouble:location.coordinate.longitude];
                 
             ];

【问题讨论】:

【参考方案1】:

嗯,也许只是在你的 GCD 中使用“afterDelay”,而不是 NSDate。

[self performSelector:@selector(geolocateGroup) 
withObject:@"Grand Central Dispatch" afterDelay:3.0];

【讨论】:

嗨@Droidnoid。感谢您的建议。使用 performSelector 和 afterDelay 结果是一样的:只有 50 个地址获得了纬度和经度信息。其他地址出现错误:kCLErrorDomain 错误 2。我认为我的代码在“一次”中触发 geolocateRoutePoint 方法 150 次,而不是在 3 秒的间隔内一个一个触发。这个performSelector的用法给了我一个思路!现在它可以工作了。谢谢!我会在稍后发布答案。 @Droidnoid:当它接受一个数组时,你为什么要向该选择器传递一个字符串 (@Grand Central Dispatch)? 很好的提示,但 1.5 秒就足够了【参考方案2】:

我在回复 Droidnoid 时想到了一个主意,它可以工作。

这里是交易:递归。地理编码完成后,它会以 3 秒的时间间隔开始一个新的地理编码请求。我现在变成了只有一种方法。

...
NSMutableArray *arrayOfRoutePoints = [[NSMutableArray alloc] initWithArray:fetchedObjects];
[self geolocateRoutePoint:arrayOfRoutePoints];
...

- (void)geolocateRoutePoint:(NSMutableArray *)mutableArrayWithRoutePoints 

if ([mutableArrayWithRoutePoints count] > 0) 
    RoutePoint *c = [mutableArrayWithRoutePoints objectAtIndex:0];

    if ([c.addressLatitude intValue] == 0) 
        CLGeocoder *geocoder = [[CLGeocoder alloc] init];
        NSString *addressString = [NSString stringWithFormat:@"%@,%@ %@ %@ %@",
                                   c.addressName,
                                   c.addressNumber,
                                   @"SOME CITY",
                                   @"SOME STATE",
                                   @"SOME COUNTRY"];

        [geocoder geocodeAddressString:addressString
                     completionHandler:^(NSArray *placemarks, NSError *error) 

                         [mutableArrayWithRoutePoints removeObjectAtIndex:0];
                         [self performSelector:@selector(geolocateRoutePoint:)
                                    withObject:mutableArrayWithRoutePoints afterDelay:3.0];

                         if (error) 
                             NSLog(@"Geocode failed with error: %@", error);
                             return;
                         

                         if (placemarks && placemarks.count > 0)
                         
                             CLPlacemark *placemark = placemarks[0];

                             CLLocation *location = placemark.location;
                             c.addressLatitude =  [NSNumber numberWithDouble:location.coordinate.latitude];
                             c.addressLongitude = [NSNumber numberWithDouble:location.coordinate.longitude];

                             // Saving the context here after getting geocode.
                             // Definitely not the best place to save the context. 
                             // I will move this later to another place
                             NSError *error = nil;
                             if (![self.managedObjectContext save:&error]) 
                                 NSLog(@"Error! %@", error);
                             
                         
                     ];
    
    else
    
        [mutableArrayWithRoutePoints removeObjectAtIndex:0];
        [self performSelector:@selector(geolocateRoutePoint:)
                   withObject:mutableArrayWithRoutePoints];
    


【讨论】:

我认为这没有考虑到这样一个事实,即通过非常快的连接,您仍然可以轻松地以每分钟超过 50 个地理编码结束。为什么不直接使用NSTimer 来遍历您的地址字符串,直到一个都没有? 问题不在于连接速度非常快,而在于我之前所说的地理编码时每分钟 50 个请求的限制。我认为 Apple 这样做的目的是防止滥用在短时间内进行大量地理编码并导致服务器过载。

以上是关于使用前向地理编码获取iOS中许多地址的纬度和经度时如何添加延迟?的主要内容,如果未能解决你的问题,请参考以下文章

快速前进地理定位和访问地标经度和经度

python中的地理编码使用API​​密钥从地址获取纬度和经度

使用 iPhone 的纬度和经度进行反向地理编码

如何在 iOS 中使用反向谷歌地理编码?

使用地理编码器根据纬度和经度检索地址会导致延迟。安卓

使用地理编码器和 android Google Maps API v2 获取纬度和经度