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.
Related
I am run in my application for finding a current location but first time return right lat long with there dependent locality but when they didUpdateLocations that time goes to didFailWithError and return Domain=kCLErrorDomain Code=0 "(null)". I have try diffrent diffrent solution like
Reset Content and Settings
In Xcode,Product -> Scheme -> Edit
Scheme,then cancel the "Allow Location Simulator"and To the iOS
Simulator and reset Content and Setting and Again to the
Xcode,repeat the first step.and To the iOS Simulator and reset.
but none of that work
my code for this is here:
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations{
NSLog(#"didUpdateToLocation: %#", [locations lastObject]);
CLLocation *currentLocation = [locations lastObject];
if (currentLocation != nil)
{
self.lblLongitude.text = [NSString stringWithFormat:#"%.12f", currentLocation.coordinate.longitude];
self.lblLatitude.text = [NSString stringWithFormat:#"%.12f", currentLocation.coordinate.latitude];
}
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];
NSString *geoMapItem = placemark.description;
NSRange start = [geoMapItem rangeOfString:#"dependentLocality"];
NSRange end = [geoMapItem rangeOfString:#")" options:NSCaseInsensitiveSearch range:NSMakeRange(start.location, 1000)];
NSString *dataString = [geoMapItem substringWithRange:NSMakeRange(start.location, end.location - start.location + end.length)];
dataString = [dataString stringByReplacingOccurrencesOfString:#"\n" withString:#""];
dataString = [dataString stringByReplacingOccurrencesOfString:#" " withString:#""];
dataString = [dataString stringByReplacingOccurrencesOfString:#"\"" withString:#""];
start = [dataString rangeOfString:#"("];
end = [dataString rangeOfString:#")"];
NSLog(#"datastring===>%#",dataString);
lblAddress.text = [NSString stringWithFormat:#"%# \n%# %#\n%#\n%#",
dataString,
placemark.postalCode, placemark.locality,
placemark.administrativeArea,
placemark.country];
} else
{
NSLog(#"%#", error.debugDescription);
}
} ];}
after update location first time goes to error block
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(#"didFailWithError%#",error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];}
and get this error didFailWithErrorError Domain=kCLErrorDomain Code=0 "(null)"
hello Guys I found The Solutions of My own question.
Some minor mistake done by me. I am check currentLocation != nil every time so, it's update location but current location Lat Long is not set.
//if (currentLocation != nil)
//{
self.lblLongitude.text = [NSString stringWithFormat:#"%.12f", currentLocation.coordinate.longitude];
self.lblLatitude.text = [NSString stringWithFormat:#"%.12f", currentLocation.coordinate.latitude];
//}
now it's Run Properly.
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];
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.
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! */
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