Reverse geocoding from given coordinates (not current location, but manually provided) - ios

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...)
// in place of the original for loop:
[self reverseGeocodeForIndex:0];
// Doing the reverse geocode is in a method so you can easily call it from within the completion block.
// Maybe your parameter is not the imgIdx value but is instead some object -- I'm just hacking your posted code
// The point is that your completion block has to be able to tell when
// it is done and how to go on to the next object when it is not done.
(void) reverseGeocodeForIndex:(int) 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){
// completion block
if(err)
{
// error stuff
}
if(placeMarks && placeMarks.count>0)
{
// what happens when you get some data
}
// now see if we are done and if not do the next object
if (imgIdx<[imageMetaMutArray count])
{
[self reverseGeocodeForIndex:imgIdx+1];
} else {
// Everything is done maybe you want to start something else
}
}];
} else {
// Since you might not reverseGeocode an object you need an else case
// here to move on to the next object.
// Maybe you could be more clever and not duplicate this code.
if (imgIdx<[imageMetaMutArray count])
{
[self reverseGeocodeForIndex:imgIdx+1];
} else {
// Everything is done maybe you want to start something else
}
}
}
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 get kCLErrorDomain code 2 error. So we avoid all that by the following approach below. Some sample code that works for me:
-(NSString *)giveMeLocName: (double)gpsLat :(double)gpsLong
{
NSString *finalLocation=[[NSString alloc]init];
//Below is URL we need to send request
NSString *reverseGeoCodeLoc = [NSString
stringWithFormat:#"http://nominatim.openstreetmap.org/reverse?format=xml&zoom=18&addressdetails=1&accept-language=en&lat=%lg&lon=%lg",gpsLat,gpsLong];
NSURL *myLocUrl = [NSURL URLWithString:reverseGeoCodeLoc];
ASIHTTPRequest *myLocRequest = [ASIHTTPRequest requestWithURL:myLocUrl];
[myLocRequest setDidFinishSelector:#selector(reverseGeoCodeImg:)];
[myLocRequest setDelegate:self];
[myLocRequest startSynchronous];
NSLog(#"waiting for location info..");
//Do stuff after receiving results here
}
//This block receives HTTP response as XML(containing reverse geo-coded info. I parse this to JSON using XMLReader class(downloadable)
-(void)reverseGeoCodeImg:(ASIHTTPRequest *)request
{
/*Allocations*/
locDict=[[NSDictionary alloc]init];
revGeoCodePart=[[NSDictionary alloc]init];
addressParts=[[NSDictionary alloc]init];
cityName=[[NSString alloc]init];
stateName=[[NSString alloc]init];
countryName=[[NSString alloc]init];
NSLog(#"starting reverse geo-code!!");
NSString *responseString = [request responseString];
NSError *parseError = nil;
locDict=[XMLReader dictionaryForXMLString:responseString error:&parseError];
[locDict retain];
revGeoCodePart=[locDict objectForKey:#"reversegeocode"];
[revGeoCodePart retain];
addressParts=[revGeoCodePart objectForKey:#"addressparts"];
[addressParts retain];
cityName=[[addressParts objectForKey:#"city"] objectForKey:#"text"];
[cityName retain];
stateName=[[addressParts objectForKey:#"state"]objectForKey:#"text"];
[stateName retain];
countryName=[[addressParts objectForKey:#"country"]objectForKey:#"text"];
[countryName retain];
NSLog(#"city: %#\nstate: %#\ncountry: %#",cityName,stateName,countryName);
}

Related

How to wait for the callBack methods (or) response in for loop (Xcode, Objective C, iOS)?

In my code i have multiple locations,I have to check all the locations are correct or not (checking with google api) if location is correct I have to get the coordinates for that location.
I am trying to write the code in for loop is there any way to wait for the response in the for loop.
I am pasting my code below.
thanks in Advance.
for (int locationsCount=0;locationsCount<results.count;locationsCount++)
{
NSString *googlelocations = [[results objectAtIndex:locationsCount]objectForKey:#"description"];
if ([locationAddress isEqualToString:googlelocations])
{
[[LocationManager share] fetchLatLngForPlacename:googlelocations placeId:[[results objectAtIndex:locationsCount] objectForKey:#"place_id"] completion:^(double lat, double lng, NSError *error)
{
[SVProgressHUD dismiss];
if (error) {
}else {
CLLocation *locationCoordinates = [[CLLocation alloc]initWithLatitude:lat longitude:lng];
NSMutableArray *globalArray = [[LocationManager share]getManualInterLocationArray];
NSMutableDictionary *dict = [[globalArray objectAtIndex:selectedTextField.tag] mutableCopy];
[dict setObject:locationCoordinates forKey:#"location_coordinates"];
[dict setObject:googlelocations forKey:#"location_Address"];
[dict setObject:[NSNumber numberWithBool:true] forKey:#"manualEntry_Flag"];
[globalArray replaceObjectAtIndex:selectedTextField.tag withObject:dict];
[[LocationManager share]saveManualInterLocationArray:globalArray];
}
}];
}
}
I used the recursive method for this requirement it's working fine now. Recursive method is the best and easy way to fulfil this requirement.
-(void)addressValidation:(int)locationCount andCompletion:(void(^)(BOOL isSuccess))callBack{
if (manualarraycount >= globalArray.count)
{
callBack(true);
return;
}
[[LocationManager share] fetchOfflineAutoCompleteSuggestionForKey:locationAddress LocationCoordinates:location Radius:duration completion:^(NSArray *results, NSError *error){
// --------- do what you want ------------
[self addressValidation:manualarraycount+1 andCompletion:callBack];
}];
}
Try to use recursion. Create a function
-(void)setLocation:(NSUInteger)locationCount andCompletion:(void (^))completionBlock{
if (locationsCount>=results.count) {
if (completion) {
completion();
}
return;
}
NSString *googlelocations = [[results objectAtIndex:locationsCount]objectForKey:#"description"];
if ([locationAddress isEqualToString:googlelocations])
{
[[LocationManager share] fetchLatLngForPlacename:googlelocations placeId:[[results objectAtIndex:locationsCount] objectForKey:#"place_id"] completion:^(double lat, double lng, NSError *error)
{
[SVProgressHUD dismiss];
if (error) {
}else {
CLLocation *locationCoordinates = [[CLLocation alloc]initWithLatitude:lat longitude:lng];
NSMutableArray *globalArray = [[LocationManager share]getManualInterLocationArray];
NSMutableDictionary *dict = [[globalArray objectAtIndex:selectedTextField.tag] mutableCopy];
[dict setObject:locationCoordinates forKey:#"location_coordinates"];
[dict setObject:googlelocations forKey:#"location_Address"];
[dict setObject:[NSNumber numberWithBool:true] forKey:#"manualEntry_Flag"];
[globalArray replaceObjectAtIndex:selectedTextField.tag withObject:dict];
[[LocationManager share]saveManualInterLocationArray:globalArray];
}
}];
}
}
In your completion block call the function itself with increment count:
[self setLocation:locationCount++ andCompletion:nil];
And to start your repeating call the function where you need starting from 0
[self setLocation:0 andCompletion:^{
// handle completion
}];
A dispatch group can be used, like in this pseudo code:
dispatch_group_t loadDetailsGroup=dispatch_group_create();
for(id thing in thingsToDo)
{
dispatch_group_enter(loadDetailsGroup);
// call method with completion callback, and in the callback run
dispatch_group_leave(loadDetailsGroup);
}
// Now outside the loop wait until everything is done. NOTE: this will block!
dispatch_group_wait(loadDetailsGroup, DISPATCH_TIME_FOREVER);
If you are running this on the main thread, you should not block it so the UI remains responsive. So you could do the wait part in the background, then possibly do something in the main thread when done:
// to background
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
// wait in background
dispatch_group_wait(loadDetailsGroup, DISPATCH_TIME_FOREVER);
// back to main (not needed if what you need to do may happen in background)
dispatch_async(dispatch_get_main_queue(),^{
// do stuff here that affects the UI
});
});
Edit: As Kurt Revis pointed out, if you want to wait asynchronously and have a callback, dispatch_group_notify() is better suited for that. So the entire above code could be condensed to:
dispatch_group_t loadDetailsGroup=dispatch_group_create();
for(id thing in thingsToDo)
{
dispatch_group_enter(loadDetailsGroup);
// call method with completion callback, and in the callback run
dispatch_group_leave(loadDetailsGroup);
}
// Now outside the loop wait until everything is done. NOTE: this will
// not block execution, the provided block will be called
// asynchronously at a later point.
dispatch_group_notify(loadDetailsGroup,dispatch_get_main_queue(),^{
// Callback
});

Unpredictable result against predicate in multithreading environment

We are developing an application to collect beacon information and sync new/updated data to the server. We are using core data to collect beacon information, but occasionally we've found that the core data framework gives incorrect results when syncing to the server. Sometimes predicates are failing after the first iteration while fetching data from the core data to sync. So, we are seeking advice about any issues you have had with prolonged use of core data and persistent storage of the database.
I am using following steps to sync core data records to server one by one
-(void)syncDataToServer{
if( !isSycInProgress ){
//predicate fetch records which newly created and which are synced to server yet
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"isSynced == %#",[NSNumber numberWithBool:NO]];
//fetch only one record at one time to utilize memory
NSArray *beaconRecordArray = [[ISCoreDataManager sharedManager] fetchObjectList:#"BeaconRecords" predicate:predicate attributeName:#"endTime" batchSize:1 offset:0 isAscending:YES inContext:mainContext];
BeaconRecords *beacon = nil;
if(beaconRecordArray.count){
isSycInProgress = YES;
beacon = [beaconRecordArray firstObject];
{
//create request parameter dictionary
NSDictionary *dict = #{
#"uid": [beacon.uID description],
#"title":beacon.title.length?beacon.title:#"No title",
#"url": beacon.urlString?beacon.urlString:#"",
};
//call webservice to upload records on server
__block NSManagedObjectID *objId = beacon.objectID;
[[WebServiceHelper sharedInstance] callPostDataWithMethod:beconUrlPostAddBecon withParameters:dict withHud:YES success:^(NSDictionary *response)
{
if([response isKindOfClass:[NSDictionary class]] && [response[#"status"] intValue] == 200){
NSString *responseStr =response[#"response_crypt_data"];
NSError *error;
//Decrypt data to fetch parameters in response
NSData *decryptedData = [RNDecryptor decryptData:[[NSData alloc] initWithBase64EncodedString:responseStr options:0] withPassword:secretKey error:&error];
DLog(#"decrypted data %#", [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding]);
//parse data
//convert data into collection format (for parsing)
NSError *parseJsonError = nil;
NSDictionary *decryptedResponse = [NSJSONSerialization JSONObjectWithData:decryptedData options:NSJSONReadingMutableContainers error:&parseJsonError];
//store Server id in local db for future reference to update record
BeaconRecords *beaconRec = [self.privateContext existingObjectWithID:objId error:nil];
[self.privateContext performBlock:^{
if(!error && !parseJsonError){
beaconRec.serverID = [NSString stringWithFormat:#"%#",decryptedResponse[#"id"]];
beaconRec.isSynced = #(YES);
[[ISCoreDataManager sharedManager] dbSaveInContext:self.privateContext];
}
//update isSynced flag in local db
isSycInProgressBeaconRecords = NO;
dispatch_async( dispatch_get_main_queue(), ^{
[self syncDataToServer]; // call this method recursively to upload all records which are pending to sync
});
}];
}
else
{
isSycInProgress = NO;
dispatch_async(dispatch_get_main_queue(), ^{
[self syncDataToServer]; // call this method recursively to upload all records which are pending to sync
});
}
} errorBlock:^(id error) {
isSycInProgress = NO;
dispatch_async(dispatch_get_main_queue(), ^{
[self syncDataToServer]; // call this method recursively to upload all records which are pending to sync
});
}];
}
return;
}
isSycInProgress = NO;
}
}
After successfully syncing 1st record to server, when I call same sync function recursively to upload 2nd record, that predicate is giving me same record which I uploaded before. And strange thing is isSynched property of fetched object is (yes) and my predicate says it should be (_NO).

Can't use the array outside the block

Hai I am writing the code inside the block to get the placemarks of the vehicle. My problem is I stored the placemarks inside the NSMutablearray but i can't access the array outside the block. kindly advice me to overcome this problem. Thanks in advance. My code is below...
CLLocation *someLocation=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:someLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if ([placemarks count] > 0) {
NSDictionary *dictionary = [[placemarks objectAtIndex:0] addressDictionary];
addressOutlet=[dictionary valueForKey:#"Street"];
City=[dictionary valueForKey:#"City"];
State=[dictionary valueForKey:#"State"];
if (addressOutlet!=NULL&&City!=NULL)
{
SubTitle=[NSString stringWithFormat:#"%#,%#,%#",addressOutlet,City,State];
}
else if (addressOutlet==NULL&&City!=NULL)
{
SubTitle=[NSString stringWithFormat:#"%#,%#",City,State];
}
else if (addressOutlet!=NULL&&City==NULL)
{
SubTitle=[NSString stringWithFormat:#"%#,%#",addressOutlet,State];
}
else if(addressOutlet==NULL&&City==NULL&&State!=NULL)
{
SubTitle=[NSString stringWithFormat:#"%#",State];
}
else if (addressOutlet==NULL&&City==NULL&&State==NULL)
{
SubTitle=[NSString stringWithFormat:#"%#",#""];
}
[storeArray addObject:SubTitle];
}
NSLog(#"%#",storeArray);// I can access here
}];
NSLog(#"%#",storeArray);// Here it shows empty array
}
What you should know is the execution-flow.
In ancient programs, the code execution flown always from top to bottom. Anyway, this premise broken a long time ago. Modern programs are built with several components, such as function, class, and blocks(closure), and the program does not always flow top to bottom. (well, though it mostly does)
A block(closure) is one of this non-sequential program. You save a code block into a variable to execute it later. The point is, the code block is not being executed when it is being defined.
What you did here is:
Make an empty array.
Create and pass a code block which fills the array into a method.
Print the array using NSLog.
At the point of #2, the code block is not executed immediately, but will be executed when the operation will be completed. Then, the array is not yet filled when you printed it, then it prints just an empty array.
You should treat the code block defined at #2 will be executed at unknown future point of time, and you really can't control the timing. This is a bad point of asynchronous programming, and something you need to be familiar with.
This is due to block.
The Array you collected is on asynch executed some time after the process happens.
But the outer log gets executed before the completion and collection of data and hence it returns no value and doesn't print anything
[geocoder reverseGeocodeLocation:someLocation completionHandler:^(NSArray *placemarks, NSError *error) {
//Some process collecting values in array
[storeArray addObject:SubTitle];
}
NSLog(#"%#",storeArray);// I can access here
//Do everything here after data gets populated
[tableview reloadData];
}];
//Here no values exist since execuion of this happens before the inner block execution
}
That's because reverseGeocodeLocation:completionHandler method is executed asynchronously, and in your case the second NSLog get called earlier then the first one which is in completion block.
Check this: Obj-C blocks
---------EDIT-----------
You must continue your logic in completion block (i.e. when you call NSLog at first time).
-(void)downloadLocations:(void(^)(void))callback
{
storeArray = [[NSMutableArray alloc] init];
//...
for(int f=0;f<Vehicle_No.count;f++){
//...
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:someLocation completionHandler:^(NSArray *placemarks, NSError *error) {
//...
NSLog(#"%#",storeArray);// I can access here
if (callback) {
callback();
}
}];
}
}
- (void)foo
{
//...
[self downloadLocations:^{
//do something here with storeArray
}];
}

reverseGeocodeLocation Only Executes Completion Block Once

I have an array of coordinates that I step through with a for loop. I would like to place annotations on a map for each location and have the subtitle for the callout be the address of the coordinate, found by using reverseGeocodeLocation In the for loop, I call the reverseGeocodeLocation method, and inside the completion block I create the annotation and display it on the map. However, when I run the app, only one annotation shows up. I went in the debugger, and the completion block is only getting called once (for two calls to the reverseGeocodeLocation method). Any suggestions to fix this?
My for loop:
for(int i = 0; i < [locations count]; i++)
{
CLLocation *location = [locations objectAtIndex:i];
__block NSString *info;
NSLog(#"Resolving the Address");
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error)
{
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0)
{
placemark = [placemarks lastObject];
info = [NSString stringWithFormat:#"%# %# %# %#, %#",
placemark.subThoroughfare, placemark.thoroughfare,
placemark.postalCode, placemark.locality,
placemark.administrativeArea];
[self remainderOfMethod:location withAddress:info atIndex:i];
}
else
{
NSLog(#"%#", error.debugDescription);
}
} ];
}
And the method called at the completion block:
- (void) remainderOfMethod: (CLLocation *)location withAddress:(NSString *)info atIndex: (int)i
{
MKPointAnnotation* annotation = [[MKPointAnnotation alloc] init];
if (location != nil)
{
[annotation setSubtitle:[NSString stringWithFormat:#"%#", info]];
annotation.coordinate = location.coordinate;
[self.mapView addAnnotation:annotation];
}
}
Thanks!
From the official Apple documentation:
After initiating a reverse-geocoding request, do not attempt to
initiate another reverse- or forward-geocoding request
You can find the docs here: https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLGeocoder_class/Reference/Reference.html#//apple_ref/occ/instm/CLGeocoder/reverseGeocodeLocation:completionHandler:
One way to solve it is to do only one request at a time in a recursive method that pops a location from a stack (or array) on each iteration.
Even in that case, consider what Apple has to say about it:
Geocoding requests are rate-limited for each app, so making too many
requests in a short period of time may cause some of the requests to
fail
So you may want to request geocoding on demand, for example when a user taps on an annotation.

reverse geocode function not executing?

I am trying to use reverse geocode but the function is not executing and not really sure why..
Here I attached my code. Thank you for your help
//-- reverse geocode, converting from point to address
- (BNRMapPoint *)geocodeLocation:(CLLocation *)location title:(NSString *)title
{
if(!geocoder)
{
geocoder = [[CLGeocoder alloc] init];
}
__block BNRMapPoint * annotation;
[self.geocoder reverseGeocodeLocation:location completionHandler:
^(NSArray * placeMarks, NSError * errors)
{
NSLog(#"in block code");
if([placeMarks count] > 0)
{
NSLog(#"%#", [placeMarks objectAtIndex:0]);
annotation = [[BNRMapPoint alloc] initWithCoordinate:location.coordinate title:title
placeMark:[placeMarks objectAtIndex:0]];
NSLog(#"%#", annotation.placeMark.name);
}
else
{
NSLog(#"failed!!");
}
}];
return annotation;
}
it is not printing anything at console.. so I figured it's not entering the block code.
But I am really confused why it's not entering. Thank you again for your help
I seem to remember having a problem with NSLog in a block passed to reverseGeocodeLocation. The Geocoder executes on a separate thread, as will the block, I expect. (I'm sure someone will correct me if I'm wrong about that). In my case, I think `UIAlertView worked even in the block code, so you might try that ...
I reviewed your code against an app I have that's working with reverseGeocodeLocation and I don't see a problem with your code. The only difference is that I do a check for if (![geocoder isGeocoding])... before I do the reverseGeocode. That's just to keep geoCoder calls from stacking up, which may not be possible in your app depending on how your code gets called.
Possibly self.geocoder = nil?
replace
if(!geocoder)
{
geocoder = [[CLGeocoder alloc] init];
}
with
if(!self.geocoder)
{
self.geocoder = [[CLGeocoder alloc] init];
}

Resources