reverse Geolocation : Postal Code Issues - objective-c

This code I am using to get the entire Address of the user using Reverse Geolocation. Can someone suggest me the way to just get the Postal Code or Zip code out of it .
//Geocoding Block
[self.geoCoder reverseGeocodeLocation: locationManager.location completionHandler:
^(NSArray *placemarks, NSError *error) {
//Get nearby address
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
//Print the location to console
NSLog(#"I am currently at %#",locatedAt);
//Set the label text to current location
[locationLabel setText:locatedAt];
}];

Use google maps to convert the geo location to a zip adress.
https://developers.google.com/maps/documentation/geocoding/

Related

Objective-C - Search for streets based on user-entered query

I want to allow the users to search for a street name and have the results displayed in a UITableView.
For the moment the region is not important, it can be from any region.
I could not find any relevant example in my searches and I don't know if I should use CLLocation or MKLocalSearch.
Based on docs, I should use MKLocalSearch:
Although local search and geocoding are similar, they support
different use cases. Use geocoding when you want to convert between
map coordinates and a structured address, such as an Address Book
address. Use local search when you want to find a set of locations
that match the user’s input.
But I have tried both methods and it gives me only 1 result (even-though there is an NSArray returned.
This is the CLGeocoder approach:
CLGeocoder *geocoding = [[CLGeocoder alloc] init];
[geocoding geocodeAddressString:theTextField.text completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else {
NSLog(#"%i", [placemarks count]);
for(CLPlacemark *myStr in placemarks) {
NSLog(#"%#", myStr);
}
}
}];
And this is my MKLocalSearch try:
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = theTextField.text;
request.region = self.region;
localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){
if (error != nil) {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Map Error",nil)
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",nil) otherButtonTitles:nil] show];
return;
}
if ([response.mapItems count] == 0) {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"No Results",nil)
message:nil
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",nil) otherButtonTitles:nil] show];
return;
}
self.streets = response;
[self.streetsTableView reloadData];
}];
MKLocalSearch seems to return more than 1 response in some cases, but these are related to places not street names searches.
Thanks in advance.
This is the closest I could get. This involves using google places API Web Service.
Note: You could probably use their Google Maps API, etc. I am sure there are other ways to get this information from the various Google APIs.
NSURL *googlePlacesURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%#&location=%f,%f&sensor=true&key=API_KEY", formattedSearchText, location.coordinate.latitude,
location.coordinate.longitude]];
The response is a JSON object. Convert it to a dictionary.
NSDictionary *response = [NSJSONSerialization JSONObjectWithData:_googlePlacesResponse
options:NSJSONReadingMutableContainers error:&error];
if([[response objectForKey:#"status"] isEqualToString:#"OK"])
{
NSArray *predictions = [response objectForKey:#"predictions"];
for(NSDictionary *prediction in predictions)
{
NSArray *addressTypes = [prediction objectForKey:#"types"];
if([addressTypes containsObject:#"route"])
{
//This search result contains a street name.
//Now get the street name.
NSArray *terms = [prediction objectForKey:#"terms"];
NSDictionary *streetNameKeyValuePair = [terms objectAtIndex:0];
NSLog(#"%#",[streetNameKeyValuePair objectForKey#"value"]);
}
}
}
The possible types seem to be
Route -> Street name
Locality -> City/location name
Political -> State, etc
Geocode -> lat/long available
You could populate the table view with those predictions that ONLY contain route as an address type. This could work.
CLGeocoder simply returns address format.
Slap this in your code and play with the contents of mapitems
MKLocalSearchRequest *request = [MKLocalSearchRequest new];
request.naturalLanguageQuery = #"Pizza";
request.region = MKCoordinateRegionMake(location.coordinate, MKCoordinateSpanMake(.01, .01));
MKLocalSearch *search = [[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
NSArray *mapItems = response.mapItems;
for (MKMapItem *mapItem in mapItems) {
MKPointAnnotation *point = [MKPointAnnotation new];
point.coordinate = mapItem.placemark.coordinate;`
}
}];
The array returned contains mapItems, you can iterate over the array to pull out all the mapItems like this:
myMatchingItems = [[NSMutableArray alloc] init];
for (MKMapItem *item in response.mapItems){
[myMatchingItems addObject:item];
}
Each mapItem.placemark.thoroughfare contains the Street of the location that was found.

Change starting location when opening Apple Maps from within app

By default when opening Apple Maps through a MKMapItem it uses the device's location as the starting point but i'm trying to allow a user to add their own starting point by entering in the proper fields (address, city, state, zipcode) and passing the address string to
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
NSString *addressString = [NSString stringWithFormat:#"%# %# %# %#",
self.address.text,
self.city.text,
self.state.text,
self.zip.text];
[geocoder geocodeAddressString:addressString
completionHandler:^(NSArray *placemarks, NSError *error)
{
CLLocationCoordinate2D addressCoordinates;
if (error.code == 2)
{
UIAlertView *networkConnectionAlert = [[UIAlertView alloc] initWithTitle:#"Network Error" message:#"The internet connections appears to be offline. Ensure that data is enabled or that your device is connected to a wireless connection." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[networkConnectionAlert show];
NSLog(#"Geocode failed with error: %#", error);
return;
}
if (placemarks && placemarks.count > 0)
{
CLPlacemark *placemark = placemarks[0];
// Location of address passed in
CLLocation *location = placemark.location;
// Coordinates of address passed in
addressCoordinates = location.coordinate;
}
// Destination address dictionary values
NSDictionary *address = #{
(NSString *)kABPersonAddressStreetKey: self.address.text,
(NSString *)kABPersonAddressCityKey: self.city.text,
(NSString *)kABPersonAddressStateKey: self.state.text,
(NSString *)kABPersonAddressZIPKey: self.zip.text
};
MKPlacemark *place = [[MKPlacemark alloc] initWithCoordinate:addressCoordinates
addressDictionary:address];
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:place];
NSDictionary *options = #{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving};
[mapItem openInMapsWithLaunchOptions:options];
}];
Of course every time I run the app it uses the device's location as the starting point and the destination point as the address entered which is understandable given the code above but is there not a property that can be called to change the starting point? I know that you can change the starting address/location when you open the actual Apple Maps so I assume that there has to be a way and that I'm just doing something wrong or missing something. Any help on this would be greatly appreciated, thanks.

Issue With __block And CLGecoder in ios?

i write code of CLGecoder and the code are
-(NSString *)GetCurrentAddress:(CLLocation *)Location
{
__block NSString *locatedaddress;
CLGeocoder *Gecoder=[[CLGeocoder alloc]init];
[Gecoder reverseGeocodeLocation: Location completionHandler:
^(NSArray *placemarks, NSError *error) {
//Get address
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"Placemark array: %#",placemark.addressDictionary );
//String to address
locatedaddress = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
//Print the location in the console
NSLog(#"Currently address is: %#",locatedaddress);
}];
return locatedaddress;
}
Problem is locatedaddress inside The completionHandler Has Value But Outside Is Not ?
Any One Can Help Me ?
Thanks In Advance.
The geocoder is asynchronous -- which by definition means you cannot get the result immediately. You must use the completion handler to do whatever you want to do with the result.

Reverse Geocode using CLGeocoder

I'd like to ask for a second opinion for my solution in reverse Geocoding in getting a user's current location:
- (void)reverseGeocodeLocation:(CLLocation *)location
{
CLGeocoder* reverseGeocoder = [[CLGeocoder alloc] init];
if (reverseGeocoder) {
[reverseGeocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark* placemark = [placemarks firstObject];
if (placemark && [placemark count] > 0) {
//Using blocks, get zip code
NSString *zipCode = [placemark.addressDictionary objectForKey:(NSString*)kABPersonAddressZIPKey];
}
}];
}
else{
MKReverseGeocoder* revGeo = [[MKReverseGeocoder alloc] initWithCoordinate:location.coordinate];
revGeo.delegate = self;//using delegate
[revGeo start];
[revGeo release];
}
[reverseGeocoder release];
}
however, there seemed to be a bit of a problem...I encountered an EXC_BAD_ACCESS error pointing at:
[reverseGeocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark* placemark = ...
}];
Could you please tell me what went wrong? I received an EXC_BAD_ACCESS error.
You're not checking the error sent to the block. You're presuming that you get at least one placemark returned, but the array may be empty for some reason. That certainly could be the source of your EXC_BAD_ACCESS error.

Issue forward-geocoding multiple addresses

I am connecting to a remote web service which basically returns an XML back. I am then parsing that XML into a Property object (think real state sort of thing)
But now, the web service returns a postal code for each property alone. It does not provide a coordinate which is what I need to place an annotation in the map. I am able to geocode an address provided a postal code. However, my problem is it is not allowing me to do multiple requests
Here's my code
- (void)processProperties:(Property *)property {
[geocoder geocodeAddressString:property.postalCode
completionHandler:^(NSArray* placemarks, NSError* error){
placemark = [placemarks lastObject];
for (CLPlacemark* aPlacemark in placemarks)
{
[sublet setLatitude:aPlacemark.location.coordinate.latitude];
[sublet setLongitude:aPlacemark.location.coordinate.longitude];
}
}];
}
- (void)addAnnotations:(NSArray *)objects {
CLLocationDegrees lat;
CLLocationDegrees longitude;
CLLocationCoordinate2D mCoords;
NSString *fullAddress;
// Add the annotations found nearby
for (Property *property in objects) {
[self processProperties:property];
lat = property.latitude;
longitude = property.longitude;
fullAddress = [NSString stringWithFormat:#"%# %# %#", property.houseNumber, #" ", property.streetName];
[self createAnnotationWithCoords:mCoords :fullAddress :[NSString stringWithFormat:#"$%.2f", property.rent]];
}
zoomLevel = 0.1;
mCoords = CLLocationCoordinate2DMake(lat,longitude);
MKCoordinateRegion region = MKCoordinateRegionMake(mCoords,MKCoordinateSpanMake(zoomLevel,zoomLevel));
[self.mapView setRegion:region animated:YES];
}
For some reason it's just geocoding 1 property. Is not going through the loop accordingly.
Any ideas folks?
Use this on your Forward Geo Function. geocoder needs to be release and initialized again to start a new address, hope this helps.
- (void)processProperties:(Property *)property {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:property.postalCode
completionHandler:^(NSArray* placemarks, NSError* error){
placemark = [placemarks lastObject];
for (CLPlacemark* aPlacemark in placemarks)
{
[sublet setLatitude:aPlacemark.location.coordinate.latitude];
[sublet setLongitude:aPlacemark.location.coordinate.longitude];
}
[geocoder release];
}];
}