使用Google地理编码进行循环-高错误率-iPhone [英] For Loop with Google Geocoding - High Error Rate - 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屋!