CLLocationManager reverseGeocodeLocation Language - ios

I'm using CLLocationManager on iPhone to get the current user location, then I use reverseGeocodeLocation to convert the location to an address.
This works fine but the results are returned in the device language and I need them to always be in english.
Is there a way to get the Address string in a desired language or convert it ?
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
}

I managed to figure it out eventually so this is for those who might need it as well.
Get the "AppleLanguages" key from SUserDefaults standardUserDefaults and save it for later.
Set the "AppleLanguages key to only "en"
Grab the location (Now it's only in english)
Restore the "AppleLanguages" key from before.
//1+2
NSArray *currentLanguageArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
//get the location
//4
[[NSUserDefaults standardUserDefaults] setObject:currentLanguageArray forKey:#"AppleLanguages"];
Hope that helps

CLGeocoder provides a handy method for this exact case:
- (void)reverseGeocodeLocation:(CLLocation *)location
preferredLocale:(NSLocale *)locale
completionHandler:(CLGeocodeCompletionHandler)completionHandler;
Available in iOS 11 and above.

Related

Make address lines blank if they don't exist (Objective-C)

My app finds the user's location, and shows the address in a label. The problem is that if something doesn't exist at a certain place, a postal code for example, then the line says (null). How do I make that line blank? I suppose it has to be set to nil somehow, somewhere...
Please help!
Here's my code:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSLog(#"Location: %#", newLocation);
CLLocation *currentLocation = newLocation;
[geoCoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (error == nil && [placemarks count] > 0) {
placeMark = [placemarks lastObject];
NSString *locationString = [NSString stringWithFormat:#"%# %#\n%# %#\n%#\n%#",
placeMark.subThoroughfare,
placeMark.thoroughfare,
placeMark.postalCode,
placeMark.locality,
placeMark.administrativeArea,
placeMark.country];
locationLabel.text = locationString;
}
else {
NSLog(#"%#", error.debugDescription);
}
}];
}
This code checks all fields for nil (which causes the <null> output) and replaces nil values with an empty string.
NSString *locationString = [NSString stringWithFormat:#"%# %#\n%# %#\n%#\n%#",
placeMark.subThoroughfare ?: #"",
placeMark.thoroughfare ?: #"",
placeMark.postalCode ?: #"",
placeMark.locality ?: #"",
placeMark.administrativeArea ?: #"",
placeMark.country ?: #""];
Quick and (very) dirty solution, but ones may find it readable:
substitute placeMark.postalCode,
with
placeMark.postalCode ? placeMark.postalCode : #"",
for each element you want nothing (or whatever other string) to appear in case of nil.
Or just write custom code to check for each element in local variables.
--
Edit:
In the remote case that you actually have a string containing "(null)" the you may want to consider checking for this value substituting again each line with:
[placeMark.postalCode isEqualToString:#"(null)"]? #"" : placeMark.postalCode,
consider anyway that you should really take care of this earlier in your logic, probably some parsing went wrong when creating the placeMark object string members.
You really need to write code to check for missing fields and handle them appropriately.
Consider that if some of the items are missing there may be blank lines in the resulting string.

GMSServices GMSGeocoder reverseGeocodeCoordinate language of returned results in IOS

I have two applications which used in pair and both used GMSGeocoder from GMSServices for reverseGeocodeCoordinate search. But in first one results are coming in english, on other - in device local language. Device is the same.
I searched a lot, and found that now is no ways to make GMSGeocoder use specified language for result. It is impossible and we should use google API requests instead. But it works somehow, and i have no idea how to make second application return results in english language only.
Similar concerns mapView - different languages on the same device.
How to set english for GMSServices regardless device localization?
GMSGeocoder sent you the county name, but not the country ISO code.
You can use native CLGeocoder class to get counytyISOcode from latitude and longitude. For example:
CLLocation *location = (your location)
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:location completionHandler:
^(NSArray* placemarks, NSError* error){
if ([placemarks count] > 0)
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"Your counry is %#",placemark. ISOcountryCode);
}
}];
Copy paste answer from stackoverflow.com/a/24333593/4195406
In - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
add
NSArray *languages = [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"];
if (![[languages firstObject] isEqualToString:#"en"]) {
[[NSUserDefaults standardUserDefaults] setObject:#[#"en"] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
This works for me
In Addition to #Dren answer - it will help to add regionCode as well in the array
NSArray *languages = [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"];
if (![[languages firstObject] isEqualToString:#"he"]) {
[[NSUserDefaults standardUserDefaults] setObject:#[#"he",#"he-IL"] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
}

Objective-C get variable out of block

I'm struggling with getting a variable out of a block. Seems to be a pretty basic thing but I can't figure it out! How can I access it? e.g. usercity out of the block? Usercity is declared as NSString in .h.
[ceo reverseGeocodeLocation: loc completionHandler:
^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//NSLog(#"placemark %#",placemark);
//String to hold address
//NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
//NSLog(#"addressDictionary %#", placemark.addressDictionary);
//NSLog(#"placemark %#",placemark.region);
NSLog(#"Land %#",placemark.country); // Give Country Name
NSLog(#"City %#",placemark.locality); // Extract the city name
NSLog(#"Adresse %#",placemark.name);
//NSLog(#"location %#",placemark.ocean);
NSLog(#"Zip %#",placemark.postalCode); //ZipCode
NSLog(#"sonstiges %#",placemark.subLocality);
//Save values in variables
usercountry = placemark.country;
usercity = placemark.locality;
userzip = placemark.postalCode;
NSLog(#"usercity: %#",usercity);
//NSLog(#"location %#",placemark.location);
}
];
Is this what you're looking for?
__block NSString *userCity;
[ceo reverseGeocodeLocation: loc completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
...
userCity = placemark.locality;
}];
But if you want to actually be able to check its value outside of the block, you'll have to do so after the completion handler updates the value. Perhaps make it a property, ie. self.userCity?
Your code in the block has to store usercity where you want it. You can't "get something out" of a block, the code in the block has to do it.
You do know that a block can access all variables in the surrounding method, don't you?

iOS Force geolocation to return city name in a specific language

I've encountered a rather strange situation where the backend developer asked me to force the city name that is returned from performing a geolocation to be in a specific language? For instance have it return København instead of Copenhagen no matter what language the iOS is to. I couldn't find anything on the web regarding this. Your help will be much appreciated. Thanks
Not sure if this is the best and safest solution but you could temporarily change the locale while you make the reverse geo code call and then reset it when you are done.
NSArray *defaultLanguages = [[NSUserDefaults standardUserDefaults] valueForKey:#"AppleLanguages"];
NSArray *languages = [NSArray arrayWithObject:#"da"];
[[NSUserDefaults standardUserDefaults] setObject:languages forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = placemarks[0];
NSString *danish = placemark.country;
[[NSUserDefaults standardUserDefaults] setObject:defaultLanguages forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
}];

Error when assigning NSString variable in a block

- (NSString *) geocodeAddressFromCoordinate:(CLLocationCoordinate2D)coordinate
{
CLLocation *location = [[CLLocation alloc]initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
__block NSMutableString * address = [NSMutableString string];
geocoder = [[CLGeocoder alloc]init];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error)
{
if (error) {
NSLog(#"%#", [error localizedDescription]);
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"No results were found" message:#"Try another search" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil, nil];
alert.show;
return;
}
if ([placemarks count]>0)
{
NSLog([placemarks description]);
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(placemark.locality);
//This line makes an error
[address initWithString:placemark.locality];**
}
}];
return address;
}
Got following runtime error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* initialization method
-initWithCharactersNoCopy:length:freeWhenDone: cannot be sent to an abstract object of class __NSCFString: Create a concrete instance!'
You should never call 'initWithString:' without a matching alloc. Looks more like what you want is [address setString:placemark.locality]
You have already initialized address with this line [NSMutableString string]; so your call to [address initWithString:placemark.locality]; is trying to initialize an already initialized object.
Change this:
[address initWithString:placemark.locality];
To:
[address setString:placemark.locality];
NSString Class Reference
NSMutableString Class Reference
[address initWithString:placemark.locality];
should be something more like:
address = placemark.locality;
or
[address appendString:placemark.locality];
depending on what yu are trying to accomplish.
At this point, your string is already initialized, [NSMutableString string] is a convenience method which essential returns [[[NSMutableString alloc] init] autorelease]. You are trying to re init an already inited object, which is bad.
Change that line to [address appendString:placemark.locality];

Resources