Вместо использования цикла 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
}
Конечно, не забудьте установить свойство обратно в ноль, когда закончите (или в dealloc
), чтобы освободить память.
В случае (1) я вызываю performSelector:withObject:afterDelay
как в блоках завершения, так и в блоках ошибок, так что следующий процесс запроса / декодирования вызывается только после завершения первого. Таким образом, ваши запросы несколько сериализуются.
В случае (2) (закомментировано / отключено) я вызываю performSelector:withObject:afterDelay
сразу после метода startRequestWithCompletion:...
, поэтому он не будет ждать окончания первого запроса, чтобы выскочить следующий. Но вы будете ждать (надеюсь) достаточно долго, чтобы не достичь предела скорости GoogleAPI
Обратите внимание, что это не единственное решение, есть много других возможностей. Одним из них является использование NSOperationQueue
для постановки запросов один за другим в очередь и добавления в нее зависимостей или для планирования процесса отправки запросов в последовательную очередь GCD (да, я знаю, что я говорил вам не использовать GCD для на самом деле отправляет ваши запросы, но они все еще применяются, но по-прежнему не используют GCD + синхронные запросы, но вы можете использовать GCD для постановки в очередь блоков, которые будут вызывать [OHURLLoader startRequestWithCompletion:...]
в главном потоке один за другим, сам запрос все еще выполняется в основном потоке с помощью RunLoop)