Geocoding to UITextfield not displaying - ios

I am using reverse geocoding which works but I am trying to separate the attributes. For example I want to have zip code displayed in it's own text field.
This is what I've tried but I get a breakpoint at if([placemarks count] >0)
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
// Make sure this is a recent location event
CLLocation *newLocation = [locations lastObject];
NSTimeInterval eventInterval = [newLocation.timestamp timeIntervalSinceNow];
if(abs(eventInterval) < 30.0)
{
// Make sure the event is valid
if (newLocation.horizontalAccuracy < 0)
return;
// Instantiate _geoCoder if it has not been already
if (_geocoder == nil)
_geocoder = [[CLGeocoder alloc] init];
//Only one geocoding instance per action
//so stop any previous geocoding actions before starting this one
if([_geocoder isGeocoding])
[_geocoder cancelGeocode];
[_geocoder reverseGeocodeLocation: newLocation
completionHandler: ^(NSArray* placemarks, NSError* error)
{
if([placemarks count] > 0)
{
CLPlacemark *foundPlacemark = [placemarks objectAtIndex:0];
self.address.text =
[NSString stringWithFormat:#"%#",
foundPlacemark.description];
self.zip.text =
[NSString stringWithFormat:#"%#",
foundPlacemark.postalCode];
}
else if (error.code == kCLErrorGeocodeCanceled)
{
NSLog(#"Geocoding cancelled");
}
else if (error.code == kCLErrorGeocodeFoundNoResult)
{
self.address.text=#"No geocode result found";
}
else if (error.code == kCLErrorGeocodeFoundPartialResult)
{
self.address.text=#"Partial geocode result";
}
else
{
self.address.text =
[NSString stringWithFormat:#"Unknown error: %#",
error.description];
}
}
];

Try to handle error first by checking if its nil:
if (error) {
// handle here
NSLog(#"error: %#", error);
return; // exit statement
}
// handle code here if there was no error
and avoid strong reference cycles create a weak object of your self, when calling a object use this instnace.
__weak typeof(self) weakSelf = self;
so self.address.text=#"Partial geocode result"; will turn to weakSelf.address.text=#"some text here...";

Related

Geocoder to fill UITextField

I have an app that fills in the user location into a textfield, if the user allows location sharing. Everything works but my question is how do I get the results to be split up into multiple text fields.
Currently the "address" text field displays everything. All I want in that field is the street address, and another one for City, State, Zip, etc. Any suggestions would be appreciated! I've looked at the documentation for example for zip code I've tried
self.zip.text=
NSString *postalCode = [NSString stringWithFormat:#"%#",placemark.postalCode];
but that doesn't work
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
if(error.code == kCLErrorDenied)
{
self.address.text = #"Location information denied";
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
// Make sure this is a recent location event
CLLocation *newLocation = [locations lastObject];
NSTimeInterval eventInterval = [newLocation.timestamp timeIntervalSinceNow];
if(abs(eventInterval) < 30.0)
{
// Make sure the event is valid
if (newLocation.horizontalAccuracy < 0)
return;
// Instantiate _geoCoder if it has not been already
if (_geocoder == nil)
_geocoder = [[CLGeocoder alloc] init];
//Only one geocoding instance per action
//so stop any previous geocoding actions before starting this one
if([_geocoder isGeocoding])
[_geocoder cancelGeocode];
[_geocoder reverseGeocodeLocation: newLocation
completionHandler: ^(NSArray* placemarks, NSError* error)
{
if([placemarks count] > 0)
{
CLPlacemark *foundPlacemark = [placemarks objectAtIndex:0];
self.address.text =
[NSString stringWithFormat:#"%#",
foundPlacemark.description];
}
else if (error.code == kCLErrorGeocodeCanceled)
{
NSLog(#"Geocoding cancelled");
}
else if (error.code == kCLErrorGeocodeFoundNoResult)
{
self.address.text=#"No geocode result found";
}
else if (error.code == kCLErrorGeocodeFoundPartialResult)
{
self.address.text=#"Partial geocode result";
}
else
{
self.address.text =
[NSString stringWithFormat:#"Unknown error: %#",
error.description];
}
}
];
//Stop updating location until they click the button again
[manager stopUpdatingLocation];
}
}
You should check the reference page for CLPlacemark class.
There you will find the properties you need: postal code, locality ...
CLPlacemark *foundPlacemark = [placemarks lastObject];
NSString *subThoroughfare = [NSString stringWithFormat:#"%#",placemark.subThoroughfare];
NSString *thoroughfare = [NSString stringWithFormat:#"%#",placemark.thoroughfare];
NSString *postalCode = [NSString stringWithFormat:#"%#",placemark.postalCode];
NSString *country = [NSString stringWithFormat:#"%#",placemark.country];
NSString *locality = [NSString stringWithFormat:#"%#",placemark.locality];
NSString *administrativeArea = [NSString stringWithFormat:#"%#",placemark.administrativeArea];

Trying to geocode an address and getting kCLErrorGeocodeFoundNoResult

So I am trying to GeoCode an address and when someone types in "asdfsfdsf" it throws an error
"kCLErrorGeocodeFoundNoResult"
How can I catch the error so it doesn't show an ugly popup (i.e. with the error above) to the user?
-(void)geocodePinAddress:(NSString *)address withBlock:(void (^)(CLLocationCoordinate2D coord))block {
CLGeocoder* gc = [[CLGeocoder alloc] init];
__block CLLocationCoordinate2D coord;
[gc geocodeAddressString:address completionHandler: ^(NSArray *placemarks, NSError *error) {
// Check for returned placemarks
if (placemarks && placemarks.count > 0) {
CLPlacemark* mark = [placemarks objectAtIndex:0];
coord = mark.location.coordinate;
block(coord);
}
}];
}
Here is how you can handle geocoder domain errors :
if(placemarks.count > 0)
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
self.outputLabel.text = placemark.location.description;
}
else if (error.domain == kCLErrorDomain)
{
switch (error.code)
{
case kCLErrorDenied:
self.outputLabel.text = #"Location Services Denied by User";
break;
case kCLErrorNetwork:
self.outputLabel.text = #"No Network";
break;
case kCLErrorGeocodeFoundNoResult:
self.outputLabel.text = #"No Result Found";
break;
default:
self.outputLabel.text = error.localizedDescription;
break;
}
}
Why not just show the message if an error occurs?
- (void)geocodePinAddress:(NSString *)address withBlock:(void (^)(CLLocationCoordinate2D coord))block {
CLGeocoder *gc = [[CLGeocoder alloc] init];
__block CLLocationCoordinate2D coord;
[gc geocodeAddressString:address completionHandler: ^(NSArray *placemarks, NSError *error) {
// if there was some error geocoding
if (error) {
// display whatever message you want, however you want, here
return;
}
// Check for returned placemarks
if (placemarks && placemarks.count > 0) {
CLPlacemark* mark = [placemarks objectAtIndex:0];
coord = mark.location.coordinate;
block(coord);
}
}];
}

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.

didUpdateToLocation is never called

I want to pass information about the location of the user to another function which uses it. The delegate class MyLocation is a singleton which stores this information.
But in my code the didUpdateToLocation never gets called . Should n't it be called at least once whenever startUpdatingLocation is called even if the device is stationary?
I did check if locationmanager.location.coordinate.latitude and locationmanager.location.coordinate.longitude have the right values and they do. The location services are enabled and the user permission to access location services is also granted. I am still building for iOS 5. None of the previously given solutions seem to work for me!
Can someone please give me some idea as to why it is not working?
The code is as follows:
CLLocationManager *locationManager;
CLGeocoder *geocoder;
CLPlacemark *placemark;
#implementation MyLocation {
}
+ (id)getInstance {
static MyLocation *sharedMyLocation = nil;
static int i=0;
if(i==0){
sharedMyLocation = [[MyLocation alloc] init];
i=1;
}
return sharedMyLocation;
}
- (id)init {
if (self = [super init]) {
latitude = [[NSString alloc] init];
longitude = [[NSString alloc] init];
country = [[NSString alloc] init];
admin_area = [[NSString alloc] init];
postal_code = [[NSString alloc] init];
locality = [[NSString alloc] init];
subtfare = [[NSString alloc] init];
tfare = [[NSString alloc] init];
}
return self;
}
- (void) startupdate{
if(locationManager == nil)
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
if(geocoder == nil)
geocoder = [[CLGeocoder alloc] init];
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if(currentLocation != nil){
longitude = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
latitude = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
[locationManager stopUpdatingLocation];
// Reverse Geocoding
NSLog(#"Resolving the Address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
country = [NSString stringWithFormat:#"%#",placemark.country];
admin_area = [NSString stringWithFormat:#"%#",placemark.administrativeArea];
postal_code = [NSString stringWithFormat:#"%#",placemark.postalCode];
locality = [NSString stringWithFormat:#"%#",placemark.locality];
subtfare = [NSString stringWithFormat:#"%#",placemark.subThoroughfare];
tfare = [NSString stringWithFormat:#"%#",placemark.thoroughfare];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
}
- (NSString*) getLatitude
{
return latitude;
}
- (NSString*) getLongitude
{
return longitude;
}
- (NSString*) getCountry
{
return country;
}
- (NSString*) getAdminArea
{
return admin_area;
}
- (NSString*) getPostalCode
{
return postal_code;
}
- (NSString*) getLocality
{
return locality;
}
- (NSString*) getSubTFare
{
return subtfare;
}
- (NSString*) getTFare
{
return tfare;
}
error GPS_INTERFACE::getLatitude(char* buffer , unsigned int len)
{
id temp = [MyLocation getInstance];
[temp startupdate];
NSString* tempbuf = [temp getLatitude];
NSString *l = [NSString stringWithFormat:#"%#",tempbuf];
const char* lati= [l UTF8String];
if(strlen(lati) < len)
std::strncpy(buffer,lati,[l length]);
else
return Buffer_Insufficent;
return No_Error;
}
/* other similar getter functions! */

locationManager avoid (null) string in a Label

I have some code that find the user location and return it into a Label. In some case, the subAdministrativeArea is not available or the thoroughfare and I want to modify my string so it doesn't show (null). I tried with some if to check this but there is a problem if the (null) are more than one. Anyone has an idea about this?
Here is my current code that needs to be modified to detect if a placemark object is equal to null:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocation *currentLocation = newLocation;
[location stopUpdatingLocation];
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
countryDetected = placemark.ISOcountryCode;
placeLabel.text = [NSString stringWithFormat:#"%#, %#, %#, %#, %# %#", placemark.country, placemark.subAdministrativeArea, placemark.subLocality, placemark.postalCode, placemark.thoroughfare, placemark.subThoroughfare];
userPlace = [NSString stringWithFormat:#"%#, %#, %#, %#, %# %#", placemark.country, placemark.subAdministrativeArea, placemark.subLocality, placemark.postalCode, placemark.thoroughfare, placemark.subThoroughfare];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
}
try this one.. if placemark.subAdministrativeArea is nil then you can write your own string in if condition otherwise set the value of placemark.subAdministrativeArea to the string variable and assign that to UILable ...
UPDATE:
NSMutableString *strLblTexts = [[NSMutableString alloc] init];
if (placemark.country != nil) {
[strLblTexts appendString:placemark.country];
}
if (placemark.subAdministrativeArea != nil) {
if ([strLblTexts isEqualToString:#""]||[strLblTexts isEqual:nil]) {
[strLblTexts appendString:placemark.subAdministrativeArea];
}
else{
NSString *strtemp=[NSString stringWithFormat:#",%#",placemark.subAdministrativeArea];
NSLog(#">>>>>>>>>>>>> str temp :%#", strtemp);
[strLblTexts appendString:strtemp];
}
}
if (placemark.subLocality != nil) {
if ([strLblTexts isEqualToString:#""]||[strLblTexts isEqual:nil]) {
[strLblTexts appendString:placemark.subLocality];
}
else{
NSString *strtemp=[NSString stringWithFormat:#",%#",placemark.subLocality];
NSLog(#">>>>>>>>>>>>> str temp :%#", strtemp);
[strLblTexts appendString:strtemp];
}
}
Do same like another 3 field and at last set that value to the UILable like bellow...
placeLabel.text = strLblTexts;
Two options:
1) Use an NSMutableString and only append the non-nil values
2) Update your current solution so each parameter is like:
placemark.country ? placemark.country : #"", placemark.subAdministrativeArea ? placemark.subAdministrativeArea : #"", ...
Update: I didn't notice the commas in the original question. Due to those being there, your best option is option 1:
NSMutableString *label = [NSMutableString string];
if (placemark.country) {
[label appendString:placemark.country];
}
if (placemark.subAdministrativeArea) {
if (label.length) {
[label appendString:#", "];
}
[label appendString:placemark.subAdministrativeArea];
}
// and the rest

Resources