Getting complete ZIP Code using reverseGeocodeLocation - ios

I have used reverseGeocodeLocation to get zip code from, however, it returns only five digits, example: "94112".But here in Brazil, we have zip code with eight digits, example "08750630", but the aftermath is "08750".
How to solve this? is it possible?
My Code:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
CLLocationCoordinate2D coords = newLocation.coordinate;
lastLat = coords.latitude;
lastLng = coords.longitude;
CLGeocoder *reverse = [[CLGeocoder alloc] init];
CLLocation *location = [[CLLocation alloc] initWithLatitude:coords.latitude
longitude:coords.longitude];
lastAccuracy = newLocation.horizontalAccuracy;
lblAccuracy.text = [NSString stringWithFormat:#"%f",lastAccuracy];
if(lastAccuracy <= 10)
{
[reverse reverseGeocodeLocation:location
completionHandler:^(NSArray *placemarks, NSError *error) {
if ([placemarks count] > 0) {
CLPlacemark *place = [placemarks objectAtIndex:0];
strCEP = place.postalCode;
strLastSubLocation = place.subLocality;
strLastLocation = place.locality;
strEndereco = place.thoroughfare;
lblEndereco.text = strEndereco;
];
}
}];
}

It's possible to get the full postal code number accessing the addressDictionary property from CLPlacemark.
In this NSDictionary we can get the information we need in the values from the keys: ZIP and PostCodeExtension.

Related

Find the distance between my location and a point in ios

I am using a method to get my location:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocation *currentLocation = newLocation;
NSLog(#"%#", currentLocation);}
//new method to find the distance
-(void) zoomToNearestSpot: (NSArray *) spot location: (CLLocation *)myLocation
{
myLocation = currentLocation;
spot = chSpot;
for (int i=0; i< spot.count; i++)
{
ChargingSpots *mySpot = [spot objectAtIndex:i];
CLLocation *thePoint = [[CLLocation alloc]initWithLatitude:[mySpot.LocationLat doubleValue] longitude:[mySpot.LocationLong doubleValue]];
CLLocationDistance dist = [myLocation distanceFromLocation:thePoint];
NSLog(#"%f", dist);
you get here **distance** in meter so in assumption **20 miles = 32187 meter**
put condition such like
if(distance <= 32187)
{
// under 20 miles you can add the zoom level
}
else
{
// out of 20 miles
}
}
}
First, I need to show all of the spots on the map by zooming out according to their number then find the nearest spots and zoom in the camera on them in.
you have more the two coordinate
1) current (user Location)
2) another coordinate ..
Here distanceFromLocation: method is use for get distance between two location.
CLLocationDistance distance = [currentLOcation distanceFromLocation:anotherLocation];
for example where you need add the following lines
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentLocation = newLocation;
for (int i=0; i<chSpot.count; i++)
{
ChargingSpots *spot = [chSpot objectAtIndex:i];
NSString *locLat = spot.LocationLat;
NSString *locLong = spot.LocationLong;
CLLocation *LocationAtual = [[CLLocation alloc] initWithLatitude: locLat longitude: locLong];
CLLocationDistance distanceBetween = [currentLocation
distanceFromLocation: LocationAtual];
NSString *tripString = [[NSString alloc]
initWithFormat:#"%f",
distanceBetween];
NSLog(#"DIST: %f", tripString);
}
}
you can use this code
1.) CLLocation *loc=[[CLLocation alloc]initWithLatitude:spot.LocationLat longitude:spot.LocationLong];
2.) CLLocationDistance distanceInMeters=[currentLocation distanceFromLocation:loc];
This will help.ThankYou

Reverse geocoding appending twice - possible threading issue

So I'm doing this -
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if (newLocation != nil) {
currentLocation = newLocation;
}
currentLocationString = [[NSMutableString alloc] initWithString:#""];
geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil && [placemarks count] > 0) {
CLPlacemark* currentLocPlacemark = [placemarks lastObject];
NSLog(#"FORMATTED ADDR DICT : %#", currentLocPlacemark.addressDictionary);
[currentLocationString appendString: currentLocPlacemark.addressDictionary[#"Street"]];
[currentLocationString appendString: #" "];
[currentLocationString appendString: currentLocPlacemark.addressDictionary[#"City"]];
NSLog(#"%#", currentLocationString);
[currentLocationString appendString: #" "];
[currentLocationString appendString: currentLocPlacemark.addressDictionary[#"Country"]];
NSLog(#"CURRENTLOCATION STRING : %#", currentLocationString);
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
[locationManager stopUpdatingLocation];
}
Sometimes the currentLocationString has two copies of the same string appended, and sometimes it does not. This seems like a threading issue - what's going on? Is there a synchronized keyword in objective C, or some way of getting around this through cocoa-touch?
It happens when reverseGeocodeLocation has not finished its execution and you receive new location update. So, in the completionHandler, you will append the string in the same variable.
To avoid it, you should create the copy of currentLocationString inside the completionHandler.

How to combine individual parts of address within a place dictionary for geocoding?

At the moment, I have a place dictionary that contains values for all the different parts of a typical address, that I then pass through a geocoder. It looks like this:
[self.placeDictionary setValue:#"166 Bovet Rd" forKey:#"Street"];
[self.placeDictionary setValue:#"San Mateo" forKey:#"City"];
[self.placeDictionary setValue:#"CA" forKey:#"State"];
[self.placeDictionary setValue:#"94402" forKey:#"ZIP"];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressDictionary:self.placeDictionary completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
PFGeoPoint* userLocation = [PFGeoPoint geoPointWithLatitude:coordinate.latitude longitude:coordinate.longitude];
NSLog(#"%f,%f", userLocation.latitude, userLocation.longitude);
} else {
NSLog(#"location error");
return;
}
}];
Instead of having a separate dictionary entry for each individual part of the address, could I merge them into one string to pass through the geocoder? Something of this effect:
[self.placeDictionary setValue:#"166 Bovet Rd San Mateo CA 94402" forKey:#"Address"];
The reason I want to do this is I have a search bar in which a user is supposed to enter a location into for geocoding, and I can't divide it and extract each individual part of the address, so is there a way that I can pass the entire address like so, for geocoding?
edit: I've tried the following code and the terminal prints "location error":
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
[self.placeDictionary setValue:#"166 Bovet Rd San Mateo CA 94402" forKey:#"Address"];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressDictionary:self.placeDictionary completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
PFGeoPoint* userLocation = [PFGeoPoint geoPointWithLatitude:coordinate.latitude longitude:coordinate.longitude];
NSLog(#"%f,%f", userLocation.latitude, userLocation.longitude);
} else {
NSLog(#"location error");
return;
}
}];
[self.view endEditing:YES];
}
After taking four values for keys Street, City, State & Zip you can create an additional key manually and store complete address in it otherwise you can store all these four values in four different strings and then save them collectively for any key in dictionary.
I figured it out. I simply used the method geocodeAddressString instead.
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
NSString* address = [NSString stringWithFormat:#"166 Bovet Road San Mateo CA 94402"];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
PFGeoPoint* userLocation = [PFGeoPoint geoPointWithLatitude:coordinate.latitude longitude:coordinate.longitude];
NSLog(#"%f,%f", userLocation.latitude, userLocation.longitude);
} else {
NSLog(#"location error");
return;
}
}];
[self.view endEditing:YES];
}

Why is this CLLocationCoordinate2D variable unassignable?

I have a geocoder method and I want it to return the CLLocationCoordinate2D that it generates for me.
- (CLLocationCoordinate2D)geocode{
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(0,0);
[geocoder geocodeAddressDictionary:self.placeDictionary completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
coordinate = location.coordinate;
} else {
NSLog(#"error");
}
}];
return coordinate;
}
The line coordinate = location.coordinate produces an error however. XCode says coordinate is an unassignable variable. Anyone see what I'm doing wrong?
update:
After following sebastian's advice, I got the code to compile, however, coordinate is not being properly set. If you take a look at both of the NSLog statements i put in the method, the first one prints out the correct coordinates that I need assigned to coordinate, however as soon as the if statement exits, coordinate goes back to being set to (0,0). The second NSLog statement prints (0,0). Anyone know how I can fix this?
- (CLLocationCoordinate2D)geocode{
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
__block CLLocationCoordinate2D geocodedCoordinate = CLLocationCoordinate2DMake(0,0);
[geocoder geocodeAddressDictionary:self.placeDictionary completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
geocodedCoordinate = location.coordinate;
NSLog(#"%f, %f", coordinate.longitude, coordinate.latitude);
} else {
NSLog(#"error");
}
}];
NSLog(#"%f, %f", coordinate.longitude, coordinate.latitude);
return coordinate;
}
You have to use the __block keyword if you want to assign to a variable that was defined outside the block's scope:
__block CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(0,0);
Have a look at the Blocks and Variables section of Apple's Block Programming Topics
About the variable not getting set when it compiles:
geocodeAddressDictionary:completionHandler: runs asynchronously. That means it returns immediately but the block gets executed later, when the results are available. You need to change the way you call your methods. At the moment you are probably doing something like this
self.myCoordinate = [self geocode];
What you have to do is more like this:
- (void)geocode{
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressDictionary:self.placeDictionary completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
self.myCoordinate = location.coordinate;
NSLog(#"%f, %f", coordinate.longitude, coordinate.latitude);
} else {
NSLog(#"error");
}
}];
}
Running [self geocode] returns immediately and myCoordinate will be set when the block runs.
If you are doing it that way, note that this could lead to a reference cycle, because self is being retained by the block.

CLGeocoder reverse geocode from given location

Given a longitude and latitude not my current location how can I perform a reverse geocode lookup using GLGeocoder?
self.geoCoder = [[CLGeocoder alloc] init];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// [self.locationManager startUpdatingLocation];
[self.geoCoder reverseGeocodeLocation: locationManager.location completionHandler: ^(NSArray *placemarks, NSError *error) {
// [self.locationManager stopUpdatingLocation];
CLPlacemark *placemark = [placemarks objectAtIndex:0];
// Long address
// NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
// Short address
NSString *locatedAt = [placemark subLocality];
cell.textLabel.text = spot.name;
cell.detailTextLabel.text = [NSString stringWithFormat:#"Cab no: %#, spotted at %#", spot.cabno, locatedAt];
}];
Will obviously only ever geocode my location, but I need to explicitly set the longitude and latitude to reverse from.
I never tried this, but can't you create your own CLLocation object?
If you know current longitude and latitude you can -
CLLocation *location = [[CLLocation alloc]initWithLatitude:someValue longitude:someValue];
[self.geoCoder reverseGeocodeLocation: location completionHandler: ^(NSArray *placemarks, NSError *error) {
//do something
});
If you use the simulator, you can debug>location>Custom Location then put in lat long to simulate a location anywhere.

Resources