I am fetching GPS information of all my images and they are stored in a Dictionary. I would pass on the lat & long values from this dictionary to the reverseGeocodeLocation
function call & store the results in my database.
The problem here is that this function is an asynchronous call & I need to synchronize the whole process for my record to get inserted into the table.
Eg: My array read following coordinates: 32.77003,96.87532. It now calls the reverseGeocodeLocation
function, passing on these coordinates as CLLocation
object. Now before this async function returns me back the geo-coded location name, next request with new set of coordinates is sent to reverseGeocodeLocation
function. This causes inconsistency to insert the record into database.
Is there any way to have this whole task turn synchronous?
i.e Make my for-loop wait until reverseGeocodeLocation
returns a value and then move on to next record to be geo-coded?
A bit of my code is here:
for (int imgIdx=0; imgIdx<[imageMetaMutArray count]; imgIdx++)
{
NSDictionary *localGpsDict = [[NSDictionary alloc]initWithDictionary: [imageMetaMutArray objectAtIndex:imgIdx]];
imgLatLoc=[localGpsDict valueForKey:@"Latitude"];
imgLongLoc=[localGpsDict valueForKey:@"Longitude"];
dateStamp=[localGpsDict valueForKey:@"DateStamp"];
timeStamp=[localGpsDict valueForKey:@"TimeStamp"];
if(imgLatLoc && imgLongLoc && dateStamp && timeStamp)
{
CLGeocoder *geoCoder=[[CLGeocoder alloc]init];
CLLocation *currentLocation=[[CLLocation alloc]initWithLatitude:[imgLatLoc doubleValue] longitude:[imgLongLoc doubleValue]];
[geoCoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placeMarks, NSError *err){
if(err)
{
NSLog(@"Reverse geo-coding failed because: %@",err);
return;
}
if(placeMarks && placeMarks.count>0)
{
CLPlacemark *placeMarkers=placeMarks[0];
NSDictionary *locationDictionary=placeMarkers.addressDictionary;
NSString *country=[locationDictionary objectForKey:(NSString *)kABPersonAddressCountryKey];
NSString *city=[locationDictionary objectForKey:(NSString *)kABPersonAddressCityKey];
NSString *state=[locationDictionary objectForKey:(NSString *)kABPersonAddressStateKey];
NSLog(@"logged in from:");
if(city)
{
NSLog(@"city: %@",city);
locName = [[NSString alloc]initWithString:city];
if(state)
{
NSLog(@"state: %@",state);
locName=[locName stringByAppendingString:@","];
locName=[locName stringByAppendingString:state];
}
if(country)
{
NSLog(@"country: %@",country);
locName=[locName stringByAppendingString:@","];
locName=[locName stringByAppendingString:country];
}
}
else
{
if(state)
{
NSLog(@"state: %@",state);
locName = [[NSString alloc]initWithString:state];
if(country)
{
NSLog(@"country: %@",country);
locName=[locName stringByAppendingString:@","];
locName=[locName stringByAppendingString:country];
}
}
else
{
NSLog(@"country: %@",country);
locName = [[NSString alloc]initWithString:country];
}
}
}
else
{
NSLog(@"Placemark Error code:: %lu\n%@",(unsigned long)placeMarks.count,placeMarks);
}
[locName retain];
NSLog(@"location decoded is: %@",locName);
/*Call for Insert into Images table*/
[self insertDataImgTbl:locName];
});
}
}
}
The short answer is that you can't make it synchronous.
What you want to do is move the code that goes on to the next object into the completion block of the reverseGeocodeLocation because that is the soonest that you can submit another reverseGeocodeLocation request. Let me see if I can make some pseudocode here... (that is, I haven't compiled this so it might not be exactly right...)
And, of course, you can't depend on this being done to do anything else except that you might kick something off when you have reverseGeocoded the last object.
This asynchronous programming can drive you nuts.
An alternative approach could be to place a synchronous request to the following URL, which returns reverse geo-coded results in XML format. You can later parse it, convert to JSON or whatever. The best part: 1) You're force synchronizing the whole process of reverse-geo coding 2) There's no restriction in terms of max requests you can make(I think its 50/min in case of calls to
reverseGeocodeLocation
handler). If exceeded, you getkCLErrorDomain
code 2 error. So we avoid all that by the following approach below. Some sample code that works for me: