iOS - LocationManager gives newLocation timestamp wrong - iphone

I just want to say that I have read everything about filtering old locations etc, but this is not the issue. What I just noticed when testing my app on a real iPhone device, was that when I change the "date & time" in "Settings" in the device, the newLocation I get from locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation gives me the same "date & time" as I have in my iPhone device.
I need to get the real timestamp according to network time, and not the phone's, because then I can manipulate the data. How on earth am I supposed to achieve this, did I miss something?
Btw, my locationmanager look like this:
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;

You won't get access to the raw GPS data (with a real timestamp). Why not use an actual ntp server instead?

Related

Iphone GPS is not giving accurate latitude and longitude

Hello Friend i have seen many post regarding accuracy problem with gps but its not working all the time
-(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSString *latstr = [NSString stringWithFormat:#"%f", newLocation.coordinate.latitude];
NSString *longstring=[NSStringstringWithFormat:#"%f",newLocation.coordinate.longitude];
if (abs(howRecent)>5.0)
{
[self.locationManager startUpdatingLocation];
return;
}
if(abs(newLocation.horizontalAccuracy)<0.0f)
{
[self.locationManager startUpdatingLocation];
return;
}
if(newLocation.horizontalAccuracy>65.0f)
{
[self.locationManager startUpdatingLocation];
return;
}
self.latstring = [latstr copy];
self.longstr = [longstring copy];
if((updateLocationFirst||loadFirstView))
{
[[NSUserDefaults standardUserDefaults]setObject:latstring forKey:#"Latitude"];
[[NSUserDefaults standardUserDefaults]setObject:longstr forKey:#"Longitude"];
[self displayParticularDaySpecial];
loadFirstView=FALSE;
updateLocationFirst=FALSE;
[self.locationManager stopUpdatingLocation];
}
}
Here the problem is I am sending the latitude and longitude to the google api with respect to some addresses if i am decreasing the accuracy value its taking lot of time to load and this value is having problem when you reach at destination with respect to destination with 0.6 miles difference.
You should refer to the Location Awareness Programming Guide which provides excellent programming examples for determining your location.
As you'll see in the demo in that document, when you start the standard location manager, you generally tell it what accuracy you require. And once you start the location manager, you don't have to start it again (like you appear to be doing in your code sample). The didUpdateLocations method will be called again and again, with increasing accuracy, all on its own. You don't need to start the location manager again ... it keeps going until you turn it off. By definition, if you're in didUpdateLocations, it means it's already on.
I also notice that you're using the old didUpdateToLocation. If you're programming for iOS 6, you really want to use didUpdateLocations, which is the current version of that CLLocationManagerDelegate method.
Finally, you mention it takes a long time to get your location. That's very possible. In fact, in certain areas, you will never get very close (or any location at all). Your app should assume that accurate locations will take a while, and you should gracefully handle if you never get a really accurate location, which is very possible.
Have you set desiredLocationAccuracy in your CLLocationManager? By default the range is somewhat wide.
It will take some time to acquire a very exact value.

Force location update

I'm attempting to overcome a sometimes-failure of didUpdateToLocation when checking local data based on current position, closing the app, traveling a bit, and opening the app again. What happens is that the user visits one place, checks the list, goes to another place, and the list is updated but using the old location data.
I would like to make sure I have a fresh newLocation.
What's wrong with this code?
double aa,bb,cc;
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
//old data? retry.
aa=[newLocation.timestamp timeIntervalSinceReferenceDate];
bb=[NSDate timeIntervalSinceReferenceDate];
cc=bb-aa; //must be <60 - minute-fresh
if (cc>60) {
[manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
[manager startUpdatingLocation]; //only stop if new reliable pos fetched.
return;
}
...handle position
}
The symptoms are that cc is about 1200 seconds on app start, then on each retry it increases a few seconds.
I've tried -[newLocation.timestamp timeIntervalSinceNow], and similarly it increases a few seconds at each retry. At one point the interval was ~2400.
I'm using FilterNone and AccuracyBest, if that could influence it.
I'm open to alternative code solutions to make sure you have a fresh position.
The answer was that you need to write the handling the way you want it to behave.
I've read up on this common problem. I should have clarified that "force" means to start unambiguous behavior that gives a reliable position under optimal conditions for the phone. Not to busy-wait until satisfied or to expect an immediate result/error code.
From a common sense viewpoint, what would be desirable by all developers would be at least an extra method to simply ask for a position within parameters, and callback only when it's valid and within accuracy, or canceled, or timed out. If the conditions prevent it you then don't need to test out esoteric behavior to be able to handle it with custom code.
Why I needed to ask about this at all was:
no existence of a method functioning as described above
using code from a book (More Iphone 3 Development)
when writing it from scratch (looking at LocateMe.xproj), discovering that:
simulator behavior differs from phone behavior (not talking about the position itself, which is obviously as good as ip lookup can make it, but the behavior of didUpdateToLocation). Recognizing the limitations of a simulator, the method should at least behave like they do on a device. But currently, correctly written location handling/checking code just times out in the simulator (as in the LocateMe example), while incorrect code (asking once and using newLocation on callback) works.
and a bug causing didUpdateToLocation being called twice after [locationManager stopUpdatingLocation];
If on top of this you (like I) load data based on your position, and the data is required by multiple views in your application, the behavior of Apple's location-fetching methods doesn't make it easy to handle the chain of update-load-calculate-present consistently and problem-free throughout the app. Especially if your stuck between user/boss perception or decision of how it should work (a rock) and how the system works (a hard place).
Here's my current code which works on a device and in a simulator:
//ask for a position, as fresh as possible.
-(void)updateMeMap {
lastloc.coordinate=homeloc.coordinate;
lm.delegate=self;
ctr=0;
[self performSelector:#selector(stopUpd) withObject:nil afterDelay:gpstimeout];
[lm startUpdatingLocation];
}
//called on each position update.
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
ctr++;
if (ctr<15) {
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"%d",ctr);
if (locationAge<60) {
NSLog(#"Found");
ctr=40;
homeloc.coordinate=newLocation.coordinate;
[self stopUpd];
[self reload];
} else {
NSLog(#"Lastupd");
lastloc.coordinate=newLocation.coordinate;
}
} else {
//enough tries, if not canceled choose lastloc.
if (ctr<40) {
NSLog(#"Last");
ctr=40;
homeloc.coordinate=lastloc.coordinate;
[self stopUpd];
[self reload];
}
}
}
//force stop updates. ctr prevents extra calls after stopUpdatingLocation.
//called after the timeout delay, if position found, cancel the timeout.
-(void)stopUpd {
[lm stopUpdatingLocation];
lm.delegate=nil;
if (ctr<15) {
ctr=40; //2 extra calls after stopupda... otherwise, now do nothing.
NSLog(#"Timeout");
homeloc.coordinate=lastloc.coordinate; //#need "copy"?
[self reload];
} else {
ctr=40; //2 extra calls after stopupda... otherwise, now do nothing.
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(stopUpd) object:nil];
}
}
// "couldn't get userlocation" handler. I also cancel like this on connectionDidFailWithError.
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"Location failed: %#",[error localizedDescription]);
ctr=0;
[self stopUpd];
}
Where ctr is there to prevent the 2 extra calls, lastloc is last known reliable position, homeloc is the phone position used for (threaded) loading of location-specific data with [self reload].
The constants 15 and 60 are safe values from real-world testing; gpstimeout is set to 30. If you work a lot in a simulator you may want to set it to something short like 3 seconds, as all you will get is a stale but relatively usable position and no more until the timeout.
Edit: If you can best my code or point out an omission, I'll mark that as answer, I hate marking my own as answer.
I've come across a similar problem in one of my previous apps.
There's no way to force a location update as far as I'm concerned - (I searched for a long time and didn't find anything)
One thing that I found was using the UIBackgroundModes key in my info.plist.
Support for some types of background execution must be declared in advance by the application that uses them. An application declares this support by including the UIBackgroundModes key in its Info.plist file. Its value is an array that contains one or more strings with the following values:
audio. The application plays audible content to the user while in the
background. (This includes streaming audio or video content using
AirPlay.)
location. The application keeps users informed of their
location, even while running in the background.
voip. The application
provides the ability for the user to make phone calls using an
Internet connection.
Which is what you're looking for. See the docs for more info.
What if you put more of the code within the age check, like:
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge<60) {
[manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
...handle position
}
}

stop location updating on iPhone

I am using following code to stop location updating
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
But still after calling thing function the location services are not stopped and still tries to find the location , can any one help me what I have done wrong.
thanks in advance.
Hopefully the following link could help you I guess.
http://www.iphonedevsdk.com/forum/iphone-sdk-development/2299-cllocationmanager-stopupdatinglocation-not-working.html
I had the same problem when it wouldn't stop updating location. I didn't try to nil the delegate though, because the problem was that in my "locationManager:didUpdateToLocation:fromLocation:" method was called other method before actually stopping updating location, i called my own method (download objects from server). It was okay until i had to download too many. I guess the deal is that it tries to download them too long for "didupdatelocation" to be called over and over again.
I thought of two solutions for that (for me at least):
Do stuff AFTER stopping manager. - That didn't work for some reason, i still had multiple calls.
Do stuff asynchronously. - That seemed to work well for me.
I hope this helps.
Normally the code you used [locationManager stopUpdatingLocation]; should work for stop updating location. But if that won't work then you can have one alternative soltion as follow:
-(void)viewDidLoad
{
firstTime = TRUE;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if(firstTime = TRUE)
{
firstTime = FALSE;
current_Latitude=newLocation.coordinate.latitude;
current_Longitude= newLocation.coordinate.longitude;
}
}
Here you can use one BOOL variable to check whether you updated the location or not.

Objective-C for Dummies: How to make App Delegate communicate with Controllers?

how can I invoke methods in my controllers from within the app delegate. For example, my application uses the app delegate to monitor the user's location. After the location has been determined I want to call a method on a controller which has a MKMapView on it and show the user's location on it. How can I go about doing that?
Here's my current code:
// AppDelegate.m
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[[[DashboardViewController alloc] initWithNibName:#"DashboardViewController" bundle:nil] displayMyLocation:newLocation.coordinate];
}
Also tried this, which is crashing with SIGABRT, but is at least attempting to call the method:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[(DashboardViewController *)dashboardViewController displayMyLocation:manager];
}
Alternatively, now that I think about it, would it be wrong to have the controller also monitor the user's location and just self invoke it's methods? If I remember correctly having multiple CLLocationManagerDelegate delegates didn't affect performance because they all access the GPS identically? Is that right or wrong? It just kinda seems dumb to have multiple instances of the same thing...
Thanks in advance!
UPDATE for #nevan
The map code:
- (void)displayMyLocation:(CLLocation *)location {
MKCoordinateSpan span;
MKCoordinateRegion region;
span.latitudeDelta = 0.02;
span.longitudeDelta = 0.02;
region.center = location.coordinate;
region.span = span;
[map setRegion:region];
}
It would certainly be a good idea to have your controller monitoring for location events.
A fairly decent alternative would be to use the notification center to notify the controller that a new location is available. I actually did exactly that in one of my applications. Check out line 70 of this file to see how to send a notification and line 54 of this file to see how tp subscribe tp these notifications.
locationManager:didUpdateToLocation is called many times, each time the device gets a new fix on the location, so you'll end up allocing and initing your DashboardViewController many times. The proper way to do this would be to alloc and init a dashboardViewController instance variable when you set up your app delegate, then use that instance variable. It looks like you've done that in your second piece of code, but I don't understand why you have to cast it to be a DashboardViewController.
It would be better again to put the location manager into the same place as your mapview. Why not move locationManager:didUpdateToLocation to there?

How to remove cache of cllocation?

I am developing an iPhone app which is a location aware app .
Currentlly the app is working fine except the caching of previous location .
The first time I start the application location manager fetches the current location and then I display nearby things based on the current location .
But from the next it uses previously fetched location and until I restart the phone it will fetch the same location . So up to this point I am clear that the location manager caches the location .
So my question is how to remove this cache and force the location manager to fetch a new location
thanks
Actually I don't think you can : it's up to you (in your CLLocationManagerDelegate instance) to filter the position you receive based on its timestamp (to ensure that the position you work on is a recent one, not a cached one).
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSDate *eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
//Is the event recent and accurate enough ?
if (abs(howRecent) < SECS_OLD_MAX) {
//WORK WITH IT !
}
....
....