CLGeocoder and backward compatibility - iphone

I have a simple question.
MKReverseCoder is deprecated and doesn't work since iOS 5. We have to use CLGeocoder. But, there are a lot of people under iOS4. How the new apps can work with iOS4 and iOS5 for geocoding ?
Thanks!

If anyone is trying to move onto CLGeocoder from MKReverseGeocoder then I have written a blog post that might be of help http://jonathanfield.me/jons-blog/clgeocoder-example.html
Basically an example would be, after you have created locationManager and CLGeocoder objects just add this code to your viewDidLoad() and then make some labels or text areas to show the data.
[super viewDidLoad]; locationManager.delegate = self; [locationManager startUpdatingLocation];
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[self.CLGeocoder reverseGeocodeLocation: locationManager.location completionHandler:
^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
isoCountryCode.text = placemark.ISOcountryCode;
country.text = placemark.country;
postalCode.text= placemark.postalCode;
adminArea.text=placemark.administrativeArea;
subAdminArea.text=placemark.subAdministrativeArea;
locality.text=placemark.locality;
subLocality.text=placemark.subLocality;
thoroughfare.text=placemark.thoroughfare;
subThoroughfare.text=placemark.subThoroughfare;
//region.text=placemark.region;
}];

MKReverseGeocoder still works with iOS5. It's just deprecated, which means it'll be removed at some later point (like at the release of something like iOS6). So you can continue to use it now without any issues

- (IBAction)geoCodeLocation:(id)sender{
[self.geoCoder reverseGeocodeLocation: locationManager.location 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(#"placemark %#",placemark.country); // Give Country Name
NSLog(#"placemark %#",placemark.locality); // Extract the city name
NSLog(#"location %#",placemark.name);
NSLog(#"location %#",placemark.ocean);
NSLog(#"location %#",placemark.postalCode);
NSLog(#"location %#",placemark.subLocality);
NSLog(#"location %#",placemark.location);
//Print the location to console
NSLog(#"I am currently at %#",locatedAt);
//Set the label text to current location
[locationLabel setText:locatedAt];
}];
For more see property of CLPlacemark

Related

set a constant language to CLPlacemark instance class

i have looked every where and didn't found an answer for this one.
i'm building an iOS app that uses the location (lat + long) of the user
creating a CLPlacemark, and sends the street + country to the server and get back a respond according to this location.
now the server can get only hebrew values, and the CLPlacemark values are changes according to the operation system of the user.
can i set a const language to the CLPlacemark class instance?
i want that the CLPlacemark will return hebrew regardless from the operation system of the user
here is my code:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
geoCoder = [[CLGeocoder alloc]init];
[self.geoCoder reverseGeocodeLocation:locationManager.location completionHandler:
^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
placemark.
self.countryTextBox.text =[placemark.addressDictionary valueForKey:#"Country"];
self.citiTextBox.text =[placemark.addressDictionary valueForKey:#"City"];
self.streetTextBox.text =[placemark.addressDictionary valueForKey:#"Street"];
self.zipCodLbl.text =[placemark.addressDictionary valueForKey:#"ZIP"];
//NSLog(#"%#",placemark.addressDictionary);
NSLog(#"%#",[placemark.addressDictionary valueForKey:#"Country"]);
NSLog(#"%#",[placemark.addressDictionary valueForKey:#"City"]);
NSLog(#"%#",[placemark.addressDictionary valueForKey:#"Street"]);
NSLog(#"%#",[placemark.addressDictionary valueForKey:#"ZIP"]);
[locationManager stopUpdatingLocation];
[self.animationBar stopAnimating];
}];
}
thanks a lot.
idan.
after a hard days of searching im finally solve it.
in the view did load just add this line of code:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:#"he"] forKey:#"AppleLanguages"];
if this will help somebody - great!
Messing with user's system preference is BAD PRACTICE!!
You should use instead:
NSLocale *yourLocal = [[NSLocale alloc] initWithLocaleIdentifier:#"de"];
[geoCoder reverseGeocodeLocation: preferredLocale:yourLocal completionHandler:
^(NSArray *placemarks, NSError *error) {
}];

get nearest locations from my current location

I am currently developing a mobile application for iOS which consists a part that requires to determine the users current location and from current location, i want to find nearest locations.
Is there any way to implement this ??
I have done some coding for finding current location of user.
here is my code snippet,
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:locationManager.location
completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"reverseGeocodeLocation:completionHandler: Completion Handler called!");
if (error){
NSLog(#"Geocode failed with error: %#", error);
return;
}
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"placemarks=%#",[placemarks objectAtIndex:0]);
But my problem is, how will i get nearest other locations ?? from my current location which i already fetched.
Thanks in advance.
Try this...
MKPointAnnotation *ann=[MKPointAnnotaion alloc] init];
CLLocationCoordinate2D point = [ann coordinate];
myLocation = [[CLLocation alloc] initWithLatitude:point.latitude longitude:point.longitude];
CLLocationDistance nearByLocation=[yourCurrentLocation distanceFromLocation:myLocation];

Geocode + MKPointAnnotation not playing nicely

I'm having the weirdest issue, and it's doing my head in. A global variable which I've set up within a Singleton is reporting correctly from within the function it's set in, then as NULL from within the very next function (which is where I need to access it), but as correct from another View! So the variable is correctly set, but it's not behaving within a certain function. There is also a weird error warning being generated by the offending line (which I've marked between *).
The warning is:
Property access result unused - getters should not be used for side effects.
Apologies for the very spotty code. I'm prototyping and learning as I go, so it's a mishmash of things I've cobbled from the net. What the code does is recognise a long tap on a mapview, and then places a pin at the location (while recording the location), and I'm trying to use Geocode to show the address at the pin position.
The first function is as follows:
- (void)handleLongPress:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateBegan)
return;
CGPoint touchPoint = [gestureRecognizer locationInView:self.fullMapView];
CLLocationCoordinate2D touchMapCoordinate =
[self.fullMapView convertPoint:touchPoint toCoordinateFromView:self.fullMapView];
//save new birthplace in global variable
globalsSingle.gblBirthplace = touchMapCoordinate;
//place user location and record it
MKUserLocation *location = fullMapView.userLocation;
globalsSingle.gblCurrentLocation = location.coordinate;
//first remove any previous birthplace pin
[self removeAllPinsButUserLocation];
[self reverseGeocode];
//place new birthplace pin
MKPointAnnotation *birthPlacePin = [[MKPointAnnotation alloc] init];
birthPlacePin.coordinate = touchMapCoordinate;
birthPlacePin.title = #"My Birthplace";
**** birthPlacePin.subtitle = #"%#", globalsSingle.gblAddress; ****
[self.fullMapView addAnnotation:birthPlacePin];
NSLog(#"gblAddress = %#", globalsSingle.gblAddress);
}
The above function calls the next:
-(void)reverseGeocode {
CLGeocoder *ceo = [[CLGeocoder alloc]init];
CLLocation *loc = [[CLLocation alloc]initWithLatitude:globalsSingle.gblBirthplace.latitude longitude:globalsSingle.gblBirthplace.longitude]; //insert your coordinates
[ceo reverseGeocodeLocation: loc completionHandler:
^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
// save the address text
globalsSingle.gblAddress = locatedAt;
NSLog(#"addressDictionary %#", placemark.addressDictionary);
NSLog(#"placemark %#",placemark.region);
NSLog(#"placemark %#",placemark.country); // Give Country Name
NSLog(#"placemark %#",placemark.locality); // Extract the city name
NSLog(#"location %#",placemark.name);
NSLog(#"location %#",placemark.ocean);
NSLog(#"location %#",placemark.postalCode);
NSLog(#"location %#",placemark.subLocality);
NSLog(#"location %#",placemark.location);
//Print the location to console
NSLog(#"I am currently at %#",locatedAt);
NSLog(#"gblAddress from reverse Geocode = %#", globalsSingle.gblAddress);
}
];
}
What's even weirder (to me) is that the NSLog's from within reverseGeocode are all printing correctly, but the NSLog from the first function is reporting NULL, and is printing before the one from reverseGeocode even though it's (I assume) being executed second! For example, a debug output is:
2013-05-21 23:41:04.662 Project Name[5659:c07] gblAddress = (null)
2013-05-21 23:41:04.808 Project Name[5659:c07] gblAddress from reverse Geocode = Januária - MG, Brazil
Any help anyone could be bothered to offer I'd appreciate, as I'm bamboozled :)
The method reverseGeocodeLocation:completionHandler: is executed asynchronously, which means that it will move on to the next lines before it finishes.
Asynchronous vs synchronous execution, what does it really mean?
It is called asynchronously because the method reverseGeocodeLocation:completionHandler: might need some time to do it, and when it is finished, the completion block is called.
You should place the new birthplace pin only after the completion block of the reverseGeocodeLocation is called, for example inside the completion block, to ensure you have got the placemark data first before placing the pin. Or you can just update the subtitle of the newly added pin inside the completion block.
[ceo reverseGeocodeLocation: loc completionHandler:
^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
// save the address text
globalsSingle.gblAddress = locatedAt;
//place new birthplace pin
MKPointAnnotation *birthPlacePin = [[MKPointAnnotation alloc] init];
birthPlacePin.coordinate = globalsSingle.gblBirthplace;
birthPlacePin.title = #"My Birthplace";
birthPlacePin.subtitle = globalsSingle.gblAddress;
[self.fullMapView addAnnotation:birthPlacePin];
}
];
}
When you are calling [self reverseGeocode]; the rest of handleLongPress will continue to run without waiting for reverseGeocode to finish. This is why you are seeing the print functions being called in an order you weren't expecting.
[self performSelectorOnMainThread:#selector(reverseGeocode) withObject:nil waitUntilDone:YES];
If handleLongPress is running on the main thread, the above line can replace [self reverseGeocode] and should produce the expected results.

Get Location information Using CLPlaceMark And CLGeocoder

I have been completed drawing the route between two places using ClLocationCoordinate2D on map in ios 6 dynamically.Can anyone please help me out in getting the location name using CLPlacemark and CLGeocoder as reverse geocoder has been deprecated in ios 6.
you can get information like bellow with its Delegate method..
UPDATE:
First Define this variable in .h file like bellow..
NSString *postcode,*locationName;
and use it in bellow method...
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLGeocoder * geoCoder = [[CLGeocoder alloc] init];
[geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
for (CLPlacemark * placemark in placemarks) {
postcode = [placemark postalCode];
[postcode retain];
locationName = [placemark name];
[locationName retain];
NSLog(#"\n placemark %#",placemarks);
}
}];
[geoCoder release];
NSLog(#"\n Location Name ==> %# ----> GotPostCode:%#",locationName,postcode);
}
here you can also use other property of CLGeocoder like locality,location,etc...
A CLPlacemark object stores placemark data for a given latitude and longitude. Placemark data includes information such as the country, state, city, and street address associated with the specified coordinate.
Check Link

Forward Geocoding with CLGeocoder Issues

I'm having an issue using forward geocoding on iOS5 with the geocodeAddressString function.
I have a MKMapView open up as a modal view to display different locations with data grabbed from the internet. My issue is when I dismiss the modal view, and then open it up again. On second try, only about half of my annotations are actually placed on the map. On a third try, none show up.
I have a feeling my issue here has to do with memory management and the scope of the CLGeocoder, but I just can't figure it out.
I create all of my annotations in the ViewDidLoad function of the view controller containing the MapView. Here is the code I use to get the coordinates of the addresses:
int locationCount = 0;
for(NSDictionary *date in locations)
{
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:[NSString stringWithFormat:#"%#, %#", [date objectForKey:#"venue"], [date objectForKey:#"location"]] completionHandler:^(NSArray *placemarks, NSError *error)
{
// if we find the exact location (including the venue string), create an annotation for the map
if(placemarks && placemarks.count > 0)
{
CLPlacemark *topResult = [placemarks objectAtIndex:0];
TourAnnotation *placemarkAnnotation = [[TourAnnotation alloc] initWithLocation:topResult.location andDetails:date];
placemarkAnnotation.tag = locationCount;
[tourMap addAnnotation:placemarkAnnotation];
}
// if not place an annotation at the center of the city
else
{
[geocoder geocodeAddressString:[date objectForKey:#"location"] completionHandler:^(NSArray *placemarks, NSError *error)
{
if(placemarks && placemarks.count > 0)
{
CLPlacemark *topResult = [placemarks objectAtIndex:0];
TourAnnotation *placemarkAnnotation = [[TourAnnotation alloc] initWithLocation:topResult.location andDetails:date];
placemarkAnnotation.tag = locationCount;
[tourMap addAnnotation:placemarkAnnotation];
}
}];
}
}];
++locationCount;
}
Any suggestions would be appreciated.
If it's memory issues have you considered how the annotation are dequeued and reused, the map view has a delegate method to do such a thing.
This tutorial may be of some assistance.
Ray Wenderlich map tutorial