localization of places for Reverse Geocoding ios - ios

I am using apple map, My app has multiple languages and I want to change the name of the location in the language selected within the app. I am getting detailed information of locality using CLPlacemark via reversegeocoding.
Here is my code
CLPlacemark *placemarker = [placemarks lastObject];
NSString *locality = placemarker.thoroughfare ?: placemarker.subLocality ?: placemarker.locality;
but I am unable to get place name in selected language of the app.

Got solution to my own problem working fine, Here is my code
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:[[REAAppSettingsController sharedInstance] languageTag], nil] forKey:#"AppleLanguages"];
[self.geocoding reverseGeocodeLocation:testLocation completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemarker = [placemarks lastObject];
NSString *locality = placemarker.thoroughfare ?: placemarker.subLocality ?: placemarker.locality;
if (locality)
{
completion(locality);
}
}
}];

Related

how to get exact coordinates of given address using forward geocoding

In my application I want the exact lattitude and longitude of given address using forward geocoding in IOS in Objective-C.
I had used forward geocoding in my application but it is not giving the exact address. this is my code of forward geocoding
-(void)detectlocation:(NSString*)address
{
CLGeocoder *geocoder=[[CLGeocoder alloc]init];
[geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error)
{
if(!error)
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"%f",placemark.location.coordinate.latitude);
NSLog(#"%f",placemark.location.coordinate.longitude);
self.latitude4=placemark.location.coordinate.latitude;
self.longitude4=placemark.location.coordinate.longitude;
NSLog(#"%#",[NSString stringWithFormat:#"%#",[placemark description]]);
}
}];
}
Thanks In Advance
You can access placemark properties for a more accurate location.
This is swift, but the same is for objective-c
Declare and initiate your CLLocationMager* inside the viewDidLoad method.
I recommend to use:
#property YourCustomLocation* foundedLocation;
in order to "save" data of the place that has been found.
Then try this inside your method:
[self.geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
//if 1+ "places" have been found:
if ([placemarks count] > 0) {
//save the first place that has been found
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//save location from the placemark
CLLocation *location = placemark.location;
//save coordinates from location
CLLocationCoordinate2D coordinate = location.coordinate;
//Do more stuffs...like:
self->_foundedLocation = [[YouCustomLocation alloc]initLocationWithLatitude:coordinate.latitude Longitude:coordinate.longitude];}
}];
Remember that forward-geocoding works with blocks, so unless you use __block directive near the variable you won't be able to "save the location" on a variable declared outside the block.

How to add annotation manually to map view in iOS?

I'd like to add annotation manually (when user touch in to the particular place in map view) and to get the details of that location (latitude,longitude,address)..
as #iPrabu directed to similar post, with very good and correct answer for your problem... for second part i.e. to get details about that location..you can do something like this
-(void)getAddressFromCurruntLocation:(CLLocation *)location{
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error)
{
if(placemarks && placemarks.count > 0)
{
CLPlacemark *placemark= [placemarks objectAtIndex:0];
NSString *address = [NSString stringWithFormat:#"%# %#",[placemark country],[placemark administrativeArea]];
// you may also get locality,sublocality,subadministrativeare etc
NSLog(#"The Address Is:%#",address);
}
}];
}
Happy Coding :)

reverseGeocodeLocation country list

I'm creating a global app and one of the initial screens will detect which country the user is in. I'm using reverseGeocodeLocation for this.
[geocoder reverseGeocodeLocation:[locations lastObject] completionHandler:^(NSArray *placemarks, NSError *error)
{
CLPlacemark *placemark = [placemarks lastObject];
country = placemark.country;
[locationManager stopUpdatingLocation];
if (country != NULL) {
[self showAlert];
}
else {
[self showActionSheet];
}
}];
When in the UK placemark.country will return "United Kingdom". I'm trying to find a list of the return strings for each country. I couldn't find anything on the apple documentation.
You could write code in 2 minutes to get the list for yourself, iterate through the list of ISO country codes and then convert them from an ISO code to the country name and NSLog each one.
The name displayed would of course only be the name for the current language locale setting on your device, in your case English.

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.

CLPlacemark.locality, value changes if the device language is different

I uses CLGeocoder to decode the CLLocation from longitude/latitude to place names. It works fine. But there is still one thing bothers me. When i set the device language to English, the result of the code below:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{
/* We received the new location */
NSLog(#"Latitude = %f", newLocation.coordinate.latitude);
NSLog(#"Longitude = %f", newLocation.coordinate.longitude);
[self.geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray* placemarks, NSError* error){
MKPlacemark *placemarker = [placemarks objectAtIndex:0];
NSLog(#"%#",placemarker.locality);
}];
[self.locationManager stopUpdatingLocation];
}
is displayed in english, like : chengdu.
when i change the device language to Chinese,
placemarker.locality
returns a Chinese character value.
But what i really want is that it will always return an English character value (no Chinese character value).
I guess this is something related to the locale. Can anyone help on this? Thanks.
Usually, it is not a good practice to mess with user locales. If the device language is set to Chinese is because the user want to read Chinese characters so, why do you want to show him in English when he already told you that he want Chinese?
Anyway, if for any reason you need to force english, you can trick the geoCoder which uses the standardUserDefaults first language so you can do something like this just before calling the geoCoder method:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
This way, geoCoder will give you all the information in english.
However, this will change the user preferences so it is a best approach to give them back to where they were:
NSMutableArray *userDefaultLanguages = [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
[self.geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray* placemarks, NSError* error){
MKPlacemark *placemarker = [placemarks objectAtIndex:0];
NSLog(#"%#",placemarker.locality);
}];
[[NSUserDefaults standardUserDefaults] setObject:userDefaultLanguages forKey:#"AppleLanguages"];
As I said, you should really think why you need this, but if you really need this, that would work.
I found a nice solution
NSString *country = placemark.ISOcountryCode;
This will return the exact country no matter your locale is. For example country will be #"US" instead of #"United States"
From ios 11 you can pass a preferredLocale parameter to geocoder reverseGeocodeLocation method.
In Swift:
geocoder.reverseGeocodeLocation(
location: CLLocation,
preferredLocale: Locale?,
completionHandler: {}
)
A preferredLocale value example:
Locale(identifier: "en_US")

Resources