passing var into objective c block - ios

I'm using the reverse geocoder and I want to save info into a SQLite database but I need the latitude and longitude set by the user but it's not being passed.
I've got two doubles var called latitude and longitude and when I execute this code below, it uses "random" doubles:
CLLocation *locate = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
CLGeocoder *geoCoderCL = [[CLGeocoder alloc] init];
[geoCoderCL reverseGeocodeLocation: locate completionHandler:
^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
Controller *mController = [[Controller alloc] init];
MyObject *newposition = [[Meeting alloc]init];
[newposition setLatitude:latitude];
[newposition setLongitude:longitude];
[newposition setMName:[NSString stringWithFormat:#"%# %#",placemark.thoroughfare,placemark.subThoroughfare]];
NSLog(#"%# %#",placemark.thoroughfare,placemark.subThoroughfare);
[mController createRecentPoint:newposition];
[mController release];
[newposition release];
}];
How is supposed to do this? Thanks.

Use the following to derive the latitude and longitude from a CLPlacemark object.
CLLocationDegrees latitude = placemark.location.coordinate.latitude;
CLLocationDegrees longitude = placemark.location.coordinate.longitude;
location is a CLLocation object. coordinate is a CLLocationCoordinate2D struct and latitude and longitude are CLLocationDegrees (which is just a typdef'd double).

Related

Is it possible to add pins to map kit solely based on physical address [duplicate]

This question already has answers here:
iOS - MKMapView place annotation by using address instead of lat / long
(7 answers)
Closed 8 years ago.
Is it possible to add pins to map kit solely based on physical address or is there a way to get long and lat based on physical address
Yes, You can get lat long from the address.
Please refer this answer : iOS - MKMapView place annotation by using address instead of lat / long
Basically it does this :
NSString *location = #"some address, state, and zip";
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];
}
}
];

Address/Zip Code as NSString to CLLocation

Is there a way to convert a zip code a user enters into a textbox and convert it into a CLLocation? I am trying to compare distance between their current location and either an address or zip code and this would be easy if I can make a CLLocation out of the NSString.
the procedure called geocoding, and that is how it looks if you implement it:
NString *_address = // any address or postcode
CLGeocoder *_geocoder = [[CLGeocoder alloc] init];
[_geocoder geocodeAddressString:_address completionHandler:^(NSArray *placemarks, NSError *error) {
if (placemarks.count > 0) {
CLPlacemark *_placemark = [placemarks firstObject];
CLLocation *_location = _placemark.location;
// ... do whaterver you want to do with the location
}
}];
NOTE: the CoreLocation.framework has to be added to your project properly. you may need to handle errors in your final completion-block, I have not added such part to my code above.

CLGeocoder returns null results for city and state when using current location data

Hi I am trying to get the name of city and state using CLGeocoder. However, placemark.addressDictionary is returning me :
{
FormattedAddressLines = (
"South Atlantic Ocean"
);
Name = "South Atlantic Ocean";
Ocean = "South Atlantic Ocean";
}
and placemark is:
South Atlantic Ocean, South Atlantic Ocean # <-42.60533670,-21.93128480> +/- 100.00m, region CLCircularRegion (identifier:'<-41.51023865,-31.60774370> radius 4958095.65', center:<-41.51023865,-31.60774370>, radius:4958095.65m)
Also, NSLog of [placemark locality] and [placemark administrativeArea] shows both nil.
Also tried adding ABAdressBookUI , ABAdressBook framework and get the data as:
NSString *addressDict = ABCreateStringWithAddressDictionary(placemark.addressDictionary, NO); which returns an object with empty description.
or tried:
NSString *state = (NSString *)[placemark.addressDictionary objectForKey:kABPersonAddressStateKey]; which throws warning of incompatible pointer types.
If there is any possible solution or if I am missing something please let me know.
My code when current location button is tapped is as follows:
CLLocation *loc;
loc = [[CLLocation alloc] initWithLatitude:[KLocationManager sharedManager]._locationManager.location.coordinate.latitude longitude:[KLocationManager sharedManager]._locationManager.location.coordinate.longitude];
CLGeocoder* geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:loc completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark* placemark = [placemarks objectAtIndex:0];
if (placemark) {
NSDictionary* dic = placemark.addressDictionary;
NSString* locName = [NSString stringWithFormat:#"%#, %#", [dic objectForKey:#"City"],[dic objectForKey:#"State"]];
CLLocation* loc = placemark.location;
self.returnLocationDict = #{#"name":locName, #"location":loc};
}
}];
What am I missing here?
One way of replicating what you're experiencing is to use a CLLocation with latitude and longitude of 0,0
I ran your code by using latitude:37.3318 longitude:-122.0312 (Infinite Loop..) and it worked as expected.
Your location manager is probably not returning what you expect.

CLGeocoder ever return one placemark

I want to revive this and this question because the problem still persists for me, so I'm writing a new question.
This is my code:
- (SVGeocoder*)initWithParameters:(NSMutableDictionary*)parameters completion:(SVGeocoderCompletionHandler)block {
self = [super init];
self.operationCompletionBlock = block;
Class cl = NSClassFromString(#"CLGeocoder");
if (cl != nil)
{
if (self.geocoder_5_1 == nil) {
self.geocoder_5_1 = [[cl alloc] init];
}
NSString *address = [parameters objectForKey:kGeocoderAddress];
[self.geocoder_5_1 geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
NSMutableArray *svplacemarks = [NSMutableArray arrayWithCapacity:1];
SVPlacemark *placemark;
NSLog(#"placemarks[count] = %i", [placemarks count]);
for (CLPlacemark *mark in placemarks) {
placemark = [[SVPlacemark alloc] initWithPlacemark:mark];
[svplacemarks addObject:placemark];
}
self.operationCompletionBlock([NSArray arrayWithArray:svplacemarks],nil,error);
}];
}
else
{
self.operationRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://maps.googleapis.com/maps/api/geocode/json"]];
[self.operationRequest setTimeoutInterval:kSVGeocoderTimeoutInterval];
[parameters setValue:#"true" forKey:kGeocoderSensor];
[parameters setValue:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode] forKey:kGeocoderLanguage];
[self addParametersToRequest:parameters];
self.state = SVGeocoderStateReady;
}
return self;
}
It is my personal version (quite rough) of SVGeocoder using CLGeocoder for forward geocoding with retrocompatibility for iOS < 5.1
I use this solution because of the Google terms which prevent the use of the maps API without showing the result on a Google map.
The problem is the same one from the previously mentioned questions: CLGeocoder returns only one placemark and the log prints a nice
"placemarks[count] = 1".
My question is, does anyone know if there is another way to retrieve forward geocoding, or some other magic thing (the Apple map app shows multiple markers for the same query I do, "via roma", for example) ?
EDIT FOR ROB'S SOLUTION
Class mkLocalSearch = NSClassFromString(#"MKLocalSearch");
if (mkLocalSearch != nil)
{
NSString *address = [parameters objectForKey:kGeocoderAddress];
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = MKCoordinateRegionForMapRect(MKMapRectWorld);
request.naturalLanguageQuery = address;
MKLocalSearch *localsearch = [[MKLocalSearch alloc] initWithRequest:request];
[localsearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
NSMutableArray *svplacemarks = [NSMutableArray arrayWithCapacity:1];
SVPlacemark *placemark;
NSLog(#"response.mapItems[count] = %i", [response.mapItems count]);
for (MKMapItem *item in response.mapItems)
{
placemark = [[SVPlacemark alloc] initWithPlacemark:item.placemark];
[svplacemarks addObject:placemark];
}
self.operationCompletionBlock([NSArray arrayWithArray:svplacemarks],nil,error);
}];
}
This is an interesting solution that gives another point of view. Unfortunately, even if I set the region to worldwide, I still get a nice log
response.mapItems[count] = 1
The query was "via roma", which is a very common street name in Italy, so much so that I think we can find it in practically any Italian city.
Maybe I'm doing something wrong?
EDIT 2 - New Test:
convert World Rect to CLRegion, code from here
NSString *address = [parameters objectForKey:kGeocoderAddress];
// make a conversion from MKMapRectWorld to a regular CLRegion
MKMapRect mRect = MKMapRectWorld;
MKMapPoint neMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), mRect.origin.y);
MKMapPoint swMapPoint = MKMapPointMake(mRect.origin.x, MKMapRectGetMaxY(mRect));
float ewDelta= neMapPoint.x - swMapPoint.x;
float nsDelta= swMapPoint.y - neMapPoint.y;
MKMapPoint cMapPoint = MKMapPointMake(ewDelta / 2 + swMapPoint.x, nsDelta / 2 + neMapPoint.y);
CLLocationCoordinate2D neCoord = MKCoordinateForMapPoint(neMapPoint);
CLLocationCoordinate2D swCoord = MKCoordinateForMapPoint(swMapPoint);
CLLocationCoordinate2D centerCoord = MKCoordinateForMapPoint(cMapPoint);
CLLocationDistance diameter = [self getDistanceFrom:neCoord to:swCoord];
// i don't have the map like showed in the example so i'm trying to center the search area to the hypothetical center of the world
CLRegion *clRegion = [[CLRegion alloc] initCircularRegionWithCenter:centerCoord radius:(diameter/2) identifier:#"worldwide"];
[self.geocoder_5_1 geocodeAddressString:address inRegion: clRegion completionHandler:^(NSArray *placemarks, NSError *error) {
NSMutableArray *svplacemarks = [NSMutableArray arrayWithCapacity:1];
SVPlacemark *placemark;
NSLog(#"placemarks[count] = %i", [placemarks count]);
for (CLPlacemark *mark in placemarks) {
placemark = [[SVPlacemark alloc] initWithPlacemark:mark];
[svplacemarks addObject:placemark];
}
self.operationCompletionBlock([NSArray arrayWithArray:svplacemarks],nil,error);
}];
... and I get the usual "placemark [count] = 1"
Obviously, CLGeocoder will return multiple placemarks if the address gets multiple hits (i.e. the region is large enough such that the simple street address is ambiguous), but frequently it will find just the one match if the region is small enough or if the supplied address is unique enough.
While it's not a general purpose solution, effective iOS 6.1, you have MKLocalSearch, which does a more general lookup (including names of businesses, etc.):
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = self.mapView.region;
request.naturalLanguageQuery = textField.text;
MKLocalSearch *localsearch = [[MKLocalSearch alloc] initWithRequest:request];
[localsearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
for (MKMapItem *item in response.mapItems)
{
Annotation *annotation = [[Annotation alloc] initWithPlacemark:item.placemark];
annotation.title = item.name;
annotation.phone = item.phoneNumber;
annotation.subtitle = item.placemark.addressDictionary[(NSString *)kABPersonAddressStreetKey];
[self.mapView addAnnotation:annotation];
}
}];
I guess it all depends upon what sort of multiple hits you're expecting to receive.
There are some addresses for which CLGeocoder does return multiple placemarks. One example I've found is "Herzel 13, Haifa, Israel". I use the geocodeAddressDictionary:completionHandler: method, and get the same 2 results for the address (it can be set either as street/city/country, or just as a street - the results are the same).
It's just pretty hard to find such examples, and they may change in the future of course. For some reason, the Apple maps app shows the "Did you mean..." dialog for many more addresses.

Reverse Geocoding issues for City name in iOS

I'm able to retrieve the current location in my iPad application using,
CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error)
{
NSLog(#"-----------------Placemark is %#-----------------", placemarks);
locationLabel.text = placemarks;
}];
and the output is,
-----------------Placemark is ("South Atlantic Ocean, South Atlantic Ocean #<-42.60533670,-21.93128480> +/- 100.00m, region (identifier <-41.51023865,-31.60774370> radius 4954476.31) <-41.51023865,-31.60774370> radius 4954476.31m"
)-----------------
Can I use the same information to just get the city and the country name? instead of the long list of information?
also, the 'locationLabel.text = placemarks' gives a warning, "Incompatible pointer types assigning to 'NSString*' from 'NSArray*_strong', which I'm unable to resolve.
Yes you can.
But you doing it a little it wrong. First of all, placemarks is an array and not a string. That's why locationLabel.text = placemarks gives a warning.
Placemarks is an array of CLPlacemarks. This is because the geocoder could return multiple results for a coordinate. In the simplest condition the first item in it should be okay.
A CLPlacemark has the property addressDictionary which contains the data of this location.
You can access this data with the address property constans defined by the ABPerson header file.
For example:
Get the first placemark from the array:
CLPlacemark *place = [placemarks objectAtIndex:0];
then get the city from this placemark:
NSString *cityName = [place objectForKey: kABPersonAddressCityKey];
Don't forget to import the AVPerson header!
your can get all following place details
placeNameLabel.text = [placemarks[0] name];
addressNumberLabel.text = [placemarks[0] subThoroughfare];
addressLabel.text = [placemarks[0] thoroughfare];
neighborhoodLabel.text = [placemarks[0] subLocality];
cityLabel.text = [placemarks[0] locality];
countyLabel.text = [placemarks[0] subAdministrativeArea];
stateLabel.text = [placemarks[0] administrativeArea];
zipCodeLabel.text = [placemarks[0] postalCode];
countryLabel.text = [placemarks[0] country];
countryCodeLabel.text = [placemarks[0] ISOcountryCode];
inlandWaterLabel.text = [placemarks[0] inlandWater];
oceanLabel.text = [placemarks[0] ocean];

Resources