Iphone GPS is not giving accurate latitude and longitude - iphone

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.

Related

Improve Accuracy of Location Manager in iOS Programming

I am making an application which tracks the user. I have notice when the application goes in the background and then when you open the app it's shows the wrong current location for the user until about 5 seconds. Is there to fix that because that 5 seconds delay ruins the tracking results ( it's adds three extra miles for no reason ).
Edit: The issue wasn't actually a "bug". I have to set in my Info.plist that I want background pocessing and boom the application tracking is super Accurate. A little tutorial to do that:
Go to Info.plist
Add an New Row called "Required background modes"
Then add again a new row called "App registers for location updates"
We are Done :)
One thing you can do is check the horizontalAccuracy property on the CLLocation that you're being returned. If this is above a certain threshold then you could throw away the result and wait for a more accurate one. If it is a number of miles out then I would expect the accuracy figure to be quite large. It's most likely using a cell site to determine location rather than GPS, and the margin of error would be much greater.
In your CLLocationManagerDelegate's locationManager:didUpdateLocations: method you could do the following:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if ([locations count] > 0) {
CLLocation *lastUpdatedLocation = [locations lastObject];
CLLocationAccuracy desiredAccuracy = 1000; // 1km accuracy
if (lastUpdatedLocation.horizontalAccuracy > desiredAccuracy) {
// This location is inaccurate. Throw it away and wait for the next call to the delegate.
return;
}
// This is where you do something with your location that's accurate enough.
}
}

iOS CoreLocation CLGeocoder giving incomplete UK postcode

I've got CoreLocation finding me, and then I'm trying to run reverseGeocodeLocation to figure out the postcode. However, I'm getting an incomplete postcode (SO31 4). Normally you'd expect another two characters after the 4. Here's the code I'm using:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
[self.geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
self.postcode.text = placemark.postalCode;
if (self.postcode.text.length > 0)
[self.locationManager stopUpdatingLocation];
}];
}
Notably, I also get similar results trying the lat/long on Google Maps API, you can see here:
http://maps.googleapis.com/maps/api/geocode/json?latlng=50.87138339,-1.30983213&sensor=true
Ideally I want a full postcode. The only alternative that comes to mind is only using the first four characters but I thought I'd ask here first just incase somebody has a better idea.
They don't have the full UK postcode database so you will only ever get this resolution with the Google API's.
You need to use a full postcode database and companies like http://www.postcodeanywhere.co.uk/ sell them.
Late reply - but for what it's worth, the postcode is still a valid postcode without the last 2 letters - it just covers a wider area. It looks odd but it's still more accurate than if you drop the last number.
Just had the same problem with a zip code in Brazil.
Here we have the format 00000-000 and the property postalCode from CLPlacemark was returning only the first five digits.
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.

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.

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 !
}
....
....