I am creating a map app, and I am using the built-in forward geocoder. So far, everything is working great. When I enter an address, the geocoder converts the results beautifully into coordinates, displayed in the console with NSLog. How do I now convert these coordinates into a pin that is displayed on the map? Here is my code.
[self.geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
if ([placemarks count] > 0)
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
NSLog (#"%f %f", coordinate.latitude, coordinate.longitude);
}
}];
The simplest way is to use an MKPointAnnotation
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate:myCoordinate];
[annotation setTitle:#"My Place"];
[[self mapView] addAnnotation:annotation];
Related
I try to get coordinate from zip/postal code using objective-c in iOS, however, it always return fixed coordinates in Zhengzhou, China on my own iPhone (I guess it is the factory of Foxconn,[34.153348, 113.488374]). But it works fine on simulator.
CLGeocoder *geoCoder = [[CLGeocoder alloc] init];
[geoCoder geocodeAddressString:zipcodefield.text completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
NSLog(#"%f", coordinate.latitude);
NSLog(#"%f", coordinate.longitude);
}];
Do you guys know why? Thanks.
I'm using the below code to display addresses from an array (responseObject) as annotations on my mapview. It works, and the pin is dropped successfully from my location string, however it only shows a pin for the most recent address added to the array. How can I change my code so that it shows pins on the map for all addresses in my array instead of just the most recent one? Apologies if this is a newb question. Thanks!
viewcontroller.m
NSMutableDictionary *viewParams = [NSMutableDictionary new];
[viewParams setValue:#"u000" forKey:#"view_name"];
[DIOSView viewGet:viewParams success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.addressData = [responseObject mutableCopy];
NSString *location = self.addressData[0][#"address"];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
// region.center = placemark.region.center;
region.span.longitudeDelta /= 8.0;
region.span.latitudeDelta /= 8.0;
[self.mapView setRegion:region animated:YES];
[self.mapView addAnnotation:placemark];
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = placemark.coordinate;
point.title = self.addressData[0][#"users_name"];
point.subtitle = self.addressData[0][#"userbio"];
[self.mapView addAnnotation:point];
You are accessing only one object ?
NSString *location = self.addressData[0][#"address"];
Edited
I think you should handle your data, separated with your view. i.e. implement geocoder related code in the mapView:viewForAnnotation: method in your map view delegate. Then you should be able to create the annotations one by one and use [self.mapView addAnnotations] for all of them
For your code, which I believe is inspired by this answer, you should be able to iterate through all location addresses by something like
for (NSMutableDictionary *loc in self.addressData) {
NSString *loc = location[#"address"];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
......
}
Forgive me if the syntax is wrong for Objective C.
This question already has answers here:
Easiest way of getting reverse geocoded current location from iOS
(4 answers)
Closed 9 years ago.
I need to find the name of the user's location using latitude and longitude. The following code I have used to pin the point in location using annotation.
//MAP VIEW Point
MKCoordinateRegion myRegion;
//Center
CLLocationCoordinate2D center;
center.latitude=latitude;
center.longitude=longitude;
//Span
MKCoordinateSpan span;
span.latitudeDelta=THE_SPAN;
span.longitudeDelta=THE_SPAN;
myRegion.center=center;
myRegion.span=span;
//Set our mapView
[MapViewC setRegion:myRegion animated:YES];
//Annotation
//1.create coordinate for use with the annotation
CLLocationCoordinate2D wimbLocation;
wimbLocation.latitude=latitude;
wimbLocation.longitude=longitude;
Annotation * myAnnotation= [Annotation alloc];
myAnnotation.coordinate=wimbLocation;
This could be the simplest way
- (void)reverseGeocodeLocation {
CLLocation *someLocation=[[CLLocation alloc]initWithLatitude:20.256456 longitude:68.545656]
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:someLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if(placemarks.count){
NSDictionary *dictionary = [[placemarks objectAtIndex:0] addressDictionary];
[self.addressOutlet setText:[dictionary valueForKey:#"Street"]];
[self.cityOutlet setText:[dictionary valueForKey:#"City"]];
[self.stateOutlet setText:[dictionary valueForKey:#"State"]];
[self.zipOutlet setText:[dictionary valueForKey:#"ZIP"]];
}
}];
}
First You need to import the AddressBook/AddressBook.h
Then include the below method
-(NSString*)locationFromCoordinate:(CLLocationCoordinate2D)coordinate
{
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *loc = [[CLLocation alloc]initWithLatitude:coordinate.latitude
longitude:coordinate.longitude];
NSString *address;
[geocoder reverseGeocodeLocation:loc
completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(#"Failed with error: %#", error);
return;
}
if (placemarks.count > 0)
{
CLPlacemark *placemark = placemarks[0];
NSDictionary *addressDictionary =
placemark.addressDictionary;
address = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStreetKey];
}
return address;
}
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];
}
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.