CLLocationManager holds cache value - iphone

This part of code of CLLocationManager is used to calculate the distance travelled. But the location cache is not removed even after using timeIntervalSinceNow.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if(newLocation != nil && oldLocation != newLocation)
{
tempNewLocation = newLocation;
tempOldLocation = oldLocation;
}
NSLog(#"New Location Found");
NSLog(#"- Latitude: %f", newLocation.coordinate.latitude);
NSLog(#"- Longitude: %f", newLocation.coordinate.longitude);
NSLog(#"- Altitude: %f", newLocation.altitude);
NSLog(#"- Course: %f", newLocation.course);
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"The location age %f",locationAge);
if (locationAge > 2.0)
{
}
else
{
if (tempOldLocation.coordinate.latitude == tempNewLocation.coordinate.latitude && tempNewLocation.coordinate.longitude == tempOldLocation.coordinate.longitude)
{
NSLog(#" Fix location found ");
}
else
{
if(tempNewLocation.coordinate.latitude == tempOldLocation.coordinate.latitude && tempNewLocation.coordinate.longitude == tempOldLocation.coordinate.longitude)
{
NSLog(#"First Time Location Update");
latitudeLongitude.text = [[ NSString alloc] initWithFormat:#"%g , %g", tempNewLocation.coordinate.latitude, tempNewLocation.coordinate.longitude];
totalDistance = 0;
distance.text = #"0 miles";
}
else if ([tempNewLocation distanceFromLocation:tempOldLocation] - tempNewLocation.horizontalAccuracy >= 0)
{
totalDistance += [tempNewLocation distanceFromLocation:tempOldLocation] - (tempNewLocation.horizontalAccuracy / 2);
}
else{
totalDistance += [tempNewLocation distanceFromLocation:tempOldLocation];
}
if (totalDistance < 0) {
distance.text = #"0 miles";
}
else
milesdistance=0.000621371192*totalDistance;
distance.text = [[ NSString alloc] initWithFormat:#"%.1f", milesdistance];
odometerreading.text = [NSString stringWithFormat:#"%09.1f", milesdistance];
mileagerate.text = [[NSUserDefaults standardUserDefaults] valueForKey:#"savedstring"];
float mileagefloat=[self.mileagerate.text floatValue];
amount.text = [NSString stringWithFormat:#"%.2f",mileagefloat * milesdistance];
amountstatus.text=[NSString stringWithFormat:#"$%.2f",mileagefloat * milesdistance];
newnumber=totalDistance;
}
This code doesnt work for me, and when I start tracking, distance is calculated from the place where I last stopped the tracking.
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"The location age %f",locationAge);
if (locationAge > 2.0)

I use a counter that counts how many times didUpdateToLocation is called.
I only use the location received after at least 3 calls.
I know 3 is a magic number but i have found that the first 3 calls are cache or very inaccurate.

Take a look at the answer to this question, as it includes code from Apple's sample app "LocateMe" and provides a bit more detail as to what you are trying to do:
https://stackoverflow.com/a/12848776/346098

You want to check the timestamp property of the new CLLocation object in your delegate method. By the sounds of it are only interested in lat/long that are no older than XXX seconds.
NSTimeInterval timeInSeconds = [newLocation.timestamp timeIntervalSinceNow];
if (timeInSeconds > YOUR_CUSTOM_TIME_IN_SECONDS)
{
// Do something
}

I found the answer for removing cache. For the first time didUpdateToLocation is called, the newlocation fetches the cache value, and the old location is null.
And in the second call, newlocation value is swapped to oldlocation and the newlocation is updated. And hence to get the updated value, the function has to be called twice.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
static CLLocation *locationanalysis1;
NSLog(#"New Location Found");
NSLog(#"- Latitude: %f", newLocation.coordinate.latitude);
NSLog(#"- Longitude: %f", newLocation.coordinate.longitude);
NSLog(#"- Altitude: %f", newLocation.altitude);
NSLog(#"- Course: %f", newLocation.course);
NSDate *eventDate = newLocation.timestamp;
NSTimeInterval howRecent = -[eventDate timeIntervalSinceNow];
if (howRecent > maximumElapsedTimeForCachedLocation) {
locationanalysis1=newLocation;
return;
}
if((locationanalysis1.coordinate.latitude-oldLocation.coordinate.latitude)==0){
NSLog(#"Old Location in location analysis is %#",oldLocation);
return;
}
NSLog(#"New location accuracy %.0fm", newLocation.horizontalAccuracy);
if ((newLocation.horizontalAccuracy < 0) || (newLocation.horizontalAccuracy > 10)) return;
if(oldLocation!=NULL && newLocation!=NULL){
totalDistance += [newLocation distanceFromLocation:oldLocation];
}else return;
}

Related

Incorrect distance and route found in my walking/running app

I am working on this walking/running app which calculates distance in meters and records lat-long for further use. Now when I calculate distance I get incorrect distance every time. I have compared it with other running apps and they generally show different distance than my distance.
Here is the code that I am using:
#define kDesiredAccuracy 5.0f
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.locationManager.distanceFilter = kDesiredAccuracy;
_routes = [[NSMutableArray alloc] init];
lastKnownLocation = nil;
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// return if accuracy is less than 0 or is greater than desired accuracy.
if (newLocation.horizontalAccuracy < 0)
{
return;
}
if(newLocation.horizontalAccuracy > kDesiredAccuracy)
{
return;
}
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
CLLocationSpeed speed = [newLocation speed];
// return if stale data or user is not moving
if (locationAge > 5.0 || speed <= 0) return;
//return if first location is found
if(lastKnownLocation == nil)
{
lastKnownLocation = newLocation;
return;
}
CLLocationDistance distance = [newLocation distanceFromLocation:(self.pramDistance > 0)?lastKnownLocation:oldLocation];
if(distance > 0)
{
// save distance for future use
NSMutableDictionary *dict=[[NSMutableDictionary alloc] init];
[dict setObject:[NSString stringWithFormat:#"%g", newLocation.coordinate.latitude] forKey:#"latitude"];
[dict setObject:[NSString stringWithFormat:#"%g", newLocation.coordinate.longitude] forKey:#"longtitude"];
[dict setObject:[NSString stringWithFormat:#"%f",distance] forKey:#"distance"];
[_routes addObject:dict];
// add distance to total distance.
self.pramDistance += distance;
}
}
Once user finishes walking/running I draw rout of walk/run on map view. For this purpose I simply draw a ploy line over MKMapView using all the recorded locations.
The map view shows zig-zag line for route and distance is always incorrect. Please suggest me where I am doing wrong and what should I amend to make it work proper?
Here is the comparison (left one is other's app and right one is mine):
Try this,
Import CLLocationManagerDelegate,
CLLocation *currentLocation = self.currentLocation;
float distanceMile = [currentLocation distanceFromLocation:[[CLLocation alloc] initWithLatitude:latitude longitude:longitude]]/1609.34;
-(void)postCurrentLocationOfDevice
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
self.locationManager.delegate = self;
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
self.currentLocation = [locations objectAtIndex:0];
[self.locationManager stopUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
self.currentLocation = newLocation;
[self.locationManager stopUpdatingLocation];
}
Though I didn't get much of the help here, I found some help and idea in this question: Corelocation incorrect distances
What I did to fix the problem is:
I stored recent 5 locations in an array.
Once 5 items are stored in the array, I checked for the nearest location.
After getting nearest location I calculated distance between last best location and stored new location in last best location.
P.S.: My code is messy and naming conventions are not that generic, that's why I am not posting my code here.

Cannot get GPS location on iPhone

My app runs perfectly on the simulator and everything works fine. But now i wanted to thest it on my iPhone and i found out that the GPS funcution don't work.
Here is my code.
[super viewDidLoad];
//eigener Standort
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
eigLat = newLocation.coordinate.latitude;
eigLon = newLocation.coordinate.longitude;
eigLatString = [NSString stringWithFormat:#"%f", eigLat];
eigLonString = [NSString stringWithFormat:#"%f", eigLon];
}
And till now everything is fine. If i use NSLog i get the right coordinates.
But then i want to use my coordinates here:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
news = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:NULL];
for (x=0; x<[news count]; x++)
{
//Berechnung der Entfernung
erdradius = 6371.1;
//Koordinaten von Datenbank in String schreiben
NSString *latitude = [[news objectAtIndex:x] objectForKey:#"Latitude"];
NSString *longitude = [[news objectAtIndex:x] objectForKey:#"Longitude"];
entfernung = 0;
double lat1 = eigLat; //eigener Standort Latitude
double long1 = eigLon; //eigener Standort Longitude
double lat2 = [latitude doubleValue]; //Standort Heurigen Latitude
double long2 = [longitude doubleValue]; //Standort Heurigen Longitude
And there I get everytime 0 for lat1 and lat2. But only if I Run the App on the iPhone. On the Simulator it works fine.
Does someone know why this could be?
The problem is that you did not get yet a GPS location in real world, so
your method connectionDidFinishLoading() is called before didUpdateToLocation() was called.
Therefoe eighValue is still 0.
Check first for valid lat and longitude:
if both are 0 then you did not get a location.
I think that you must change the logic of your program code,
you have to either
1) wait till you have a location, and then start the
connection such that connectionDidFinishLoading is called after you have a GPS coordinate.
Or
2) you store the coordinate result of the network connection, and calculate when you got your first coordinate

Passing Current longitude & latitude on buttonclick event

Hello I am using CoreLocation to get latitude and longitude in my map application to get latitude and longitude by using following method
- (void)viewDidLoad {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
[super viewDidLoad];
}
The _ (void)locationManager.... method is not getting call
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
int degrees = newLocation.coordinate.latitude;
double decimal = fabs(newLocation.coordinate.latitude - degrees);
int minutes = decimal * 60;
double seconds = decimal * 3600 - minutes * 60;
NSString *lat = [NSString stringWithFormat:#"%d° %d' %1.4f\"",
degrees, minutes, seconds];
degrees = newLocation.coordinate.longitude;
decimal = fabs(newLocation.coordinate.longitude - degrees);
minutes = decimal * 60;
seconds = decimal * 3600 - minutes * 60;
NSString *longt = [NSString stringWithFormat:#"%d° %d' %1.4f\"",
degrees, minutes, seconds];
}
I want to call lati & longi on Button click event to URL. But it is not working. it passes 0000.0 lati & longi to my url. Can some one tell me how to rectify this code
I don't see any obvious problem with your init of CLLocationManager. If you are not getting callbacks perhaps it doesn't yet have a location available. You should also implement the error callback and see if it is getting called instead.
I suggest you try one of the CLLocationManager examples provided by Apple and see if you can get the example to run.
I have did this to pass latitude and longitude in to web service URL on button click...
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if((fabs(newLocation.coordinate.latitude) > 0.001) || (fabs(newLocation.coordinate.longitude) > 0.001)) {
NSLog(#"Got location %f,%f", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
if (currentLocation != nil) {
[currentLocation release];
}
currentLocation = newLocation;
[currentLocation retain];
}}
and On click event code I have just pass locationmanager.location.coordinate.latitude.....
NSString *url = [NSString stringWithFormat:#"http://.....Url..../hespdirectory/phpsqlsearch_genxml.php?lat=%f&lng=%f&radius=%f",locationManager.location.coordinate.latitude,locationManager.location.coordinate.longitude,radius];
U can directly change the CLLocation to NSString
NSString *lat=[NSString stringWithFormat:#"%f", newLocation.latitude];
NSString *lon=[NSString stringWithFormat:#"%f", newLocation.longitude];
The answers don't show it directly, but you should have assigned your controller as the CLLocationManagerDelegate to recieve the callbacks correct?

best way to get changed location iPhone sdk?

My ultimate goal is that i need to send lat and logitude to web server, every time when location changes.
I am using below code for sending lat and longitude of a device to a web server after every 2 minutes but it is not giving sometimes correct latitude and longitude as location changes.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation
{
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"Location Age%#",[NSString stringWithFormat:#"%d",locationAge]);
if (locationAge > 5) return;
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0) return;
NSString *stringUrl;
// BOOL check = FALSE;
NSLog(#"Before condition condition");
if(bestEffortAtLocation == nil || bestEffortAtLocation.horizontalAccuracy > newLocation.horizontalAccuracy){
NSLog(#"condition");
self.bestEffortAtLocation = newLocation;
if (newLocation.horizontalAccuracy <= locmanager.desiredAccuracy) {
// we have a measurement that meets our requirements, so we can stop updating the location
// IMPORTANT!!! Minimize power usage by stopping the location manager as soon as possible.
[locmanager stopUpdatingLocation];
locmanager.delegate = nil;
}
//check = TRUE;
}
stringUrl = [NSString stringWithFormat:URLSAVELAT,stringUserId,[NSString stringWithFormat:#"%g",self.bestEffortAtLocation.coordinate.latitude],[NSString stringWithFormat:#"%g",self.bestEffortAtLocation.coordinate.longitude]];}
For location manager i am using below code
{
locmanager = [[CLLocationManager alloc] init];
[locmanager setDelegate:self];
locmanager.distanceFilter = 10.0;
//locmanager.distanceFilter = kCLDistanceFilterNone;
[locmanager setDesiredAccuracy:kCLLocationAccuracyBest];
[locmanager startUpdatingLocation];
}
Any,even small help would be appreciated, Thank u in advance
You should use the location update call backs from the API and use updateLocation method:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if([self.delegate conformsToProtocol:#protocol(CoreLocationControllerDelegate)]) {
[self.delegate locationUpdate:newLocation];
}
}
Then in the viewcontroller do this:
- (void)locationUpdate:(CLLocation *)location {
//DO WHATEVER YOU WANT HERE, INCLUDING SENDING TO SERVER
}
You also need to define two protocol methods, one of which is the locationUpdate:
#protocol CoreLocationControllerDelegate
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
I would not recommend doing all that you do in the didUpdateLocation: method.

CLLocationManager didUpdateToLocation checking failing

I am trying to get the location coordinates using CLLocationManager. Here is my code
- (void)viewDidLoad {
[super viewDidLoad];
//instantiate location manager and set delegate
self.locationManager=[[CLLocationManager alloc]init];
locationManager.delegate=self;
// can be set to 100m,1km,3km etc.
//locationManager.distanceFilter=10.0f;
locationManager.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;
//start updating the delegate
[locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{
// Check if the coordinates are different from the old ones
if (newLocation.coordinate.latitude != oldLocation.coordinate.latitude &&
newLocation.coordinate.longitude != oldLocation.coordinate.longitude) {
NSLog(#"not equal");
} else {
NSLog(#"equal");
}
}
However i find the condition is called twice. First time the condition is satisfied and prints not equal and immediately its called again and prints "equal". Can some1 help me out ? What am i doing wrong ?
Thanks
This is because CoreLocation cache your last location and return it immediately after you called startUpdatingLocation so you have to validate coordinate timestamp and it is too old, you can ignore old coordinate.
UPDATE:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if([newLocation horizontalAccuracy] < 0.0f) return;
if(fabs([[newLocation timestamp] timeIntervalSinceNow]) > kCLLocationMaximumLocationDataAge) return;
if(fabs([[oldLocation timestamp] timeIntervalSinceNow]) < kCLLocationMaximumLocationDataAge && [newLocation getDistanceFrom:oldLocation] < 0.1f && [newLocation horizontalAccuracy] == [oldLocation horizontalAccuracy])
return;
if(((runningHighPreciseLocationDetectionService||runningLowPowerLocationDetectionService) && ([newLocation horizontalAccuracy] <= kCLLocationAccuracyHundredMeters))){
NSLog(#"---> \n%#\n%#\nHorizontal accurecy: %f\nLocation age: %fs\nOld location age: %fs", NSStringFromSelector(_cmd), newLocation, newLocation.horizontalAccuracy, fabs([[newLocation timestamp] timeIntervalSinceNow]), fabs([[oldLocation timestamp] timeIntervalSinceNow]));
} else {
NSLog(#"\n-------------- BAD ---------------\n%#\n%#\nHorizontal accurecy: %f\nLocation age: %fs\nOld location age: %fs\n----------------------------------", NSStringFromSelector(_cmd), newLocation, newLocation.horizontalAccuracy, fabs([[newLocation timestamp] timeIntervalSinceNow]), fabs([[oldLocation timestamp] timeIntervalSinceNow]));
}
if(((runningHighPreciseLocationDetectionService||runningLowPowerLocationDetectionService) && ([newLocation horizontalAccuracy] <= kCLLocationAccuracyHundredMeters))){
[self stopLocationImprovementTimer];
} else [self createLocatinoImprovementTimer];
}
createLocatinoImprovementTimer method used to launch timer, which will work for certain amount of time and if it wasn't stopped it will send and update notification with location, which was last. This timer will help to wait for coordinate with better accuracy before notify controllers.