GPS Location takes a few seconds to be retrieved - iphone

I have written an iPhone app that uses the iPhone's relative GPS location.
I have a button in the user interface that does reverse geolocation (pulls the street name bases on the lat and long). The only problem is that the location object as retrieved by
CLLocation *location = [[self locationManager] location];
is nil if the user taps the button too soon. I am initializing the LocationManager in viewDidLoad as I don't want to object to be created unless the user actually loads this screen. I start updating the location straight away as well... but still if the user loads the screen and taps the GPS button straight away the location is nil.
Here comes the question: do you know roughly how much time the CLLocationManager needs to retrieve the location?
Thanks

It can take the phone a few seconds to retrieve this data. For usability, you may want to deactivate the button control. Fire an NSNotification once the location is found. Register your view controller to listen for this notification, which fires a selector that re-activates the button control.

Acquiring a location fix is dependent on the amount of accuracy you want, and whether it's previously had some kind of location data, what the weather is like, whether you're inside/outside ... there really isn't one answer. If you go to the Maps application and click on the 'locate' button then you'll notice that in different circumstances, it will be some time after you start the resolution process.
The callbacks will tell you when there is data; you shouldn't get it by polling or assuming instant access (or worse, blocking the app until you expect to find data). It sounds like the key problem here is your button is synchronously executing the request and not being dynamic; in other words, a race condition guaranteed to fail at some point, regardless of what value of 'n' you come up with.
Change your code so that the button invokes the location acquisition in the background, and then subsequently pops up the information or fills out the form later.

Related

iPhone : How do I display the user location on a map view without updating location / having GPS running in the background?

how do I display the user location in a mapView while not running GPS to update the location (at all)? Will
mapView.userTrackingMode = kCLLocationAccuracyNearestTenMeters;
do the job or will GPS still burn battery in the background?
Thanks :)
I'm going to attempt to answer your question as best as i can given the limited information.
The GPS has 3 main modes that go from low power to high power, low accuracy to high accuracy.
Location Tracking off
Background location updates (uses cell towers and wifi)
GPS location updates
An MKMapView will show a blue dot for the user location if you set showsUserLocation to YES. The MKMapView will use all available location methods to find the users location as accurately as possible and keep updating it while this is set to YES.
The tracking in MKMapView, a mode which keeps the users location centred on screen, moves the visible map region as the user moves and is available in iOS5. you are given three MKUserTrackingModes to choose from. From the docs:
MKUserTrackingModeNone: The map does not follow the user location.
MKUserTrackingModeFollow: The map follows the user location.
MKUserTrackingModeFollowWithHeading: The map follows the user location
and rotates when the heading changes.
So setting it to kCLLocationAccuracyNearestTenMeters isn't going to work as it is not an available option in this context.
Will showing the location burn battery in the background? It depends on what you mean by background. When the user taps the home button the MKMapView is forced to stop using the GPS by the system. While the app is running and the MKMapView is alive and has the showsUserLocation property set to YES it will keep using any available method, including the GPS, to update the location. You have a couple of strategies to reduce this.
1) presume that the user needs to see their location updated while the map is on screen. In which case keep showsUserLocation set to YES until the map is moved off screen, or the device is locked, then set it to NO
2) Presume the user only needs to see a static marker of their location from a particular point in time, like when the app is opened. In this case you need to make a CLLocationManager object, ask it to startUpdatingLocation, filter the delegate messages for the accuracy you want, and then turn off location updates (stopUpdatingLocation). You can then add an MKAnnotation to the MKMapView to show the user their location.
As you can see number 2 is more work, yet very power efficient. Number 1 is easy, but will use more battery while the map is visible. It is up to you to decide which behaviour the user expects and to implement your app accordingly.

IOS Location found detection

Currently I'm building an application which shows nearby advertisements based on the current location. When the user starts the application for the first time I want them to see a top 10 of nearby advertisements.
I'm having a slight problem with fetching the location on time. My problem is that the current location isn't fetched yet before the view is loaded.
Of course there is the delegate UpdatedLocation, but this one gets fired multiple times. I guess it fires multiple times, because it wants to fetch the most accurate location?
So my question is; What can I do to 'wait' until the location is found and then start searching for advertisements?
Thanks in advance!
Regards,
Mittchel
You should update the view every time you get a (more accurate) location. So remember the last location and check whether horizontalAccuracy/verticalAccuracy have decreased (smaller = more accurate, but negative = invalid). Maybe even updating every time you get a new location would be better since the accuracy might not change but the position does (user is moving).
If you just show a list, you should remember the previous results. Fetch the new result and if they differ, update your list.
When CLLocationManager gets an updated hit from the Core Location system, it fires its delegate's didUpdateToLocation:fromLocation: method. Inside that method, you want to do whatever you do when you get an updated location.
In your case, you'll want to check that new location's .horizontalAccuracy property to see that it's a high quality result. You also probably want to chuck the first few, because CL will give you the last hit of the last location session as your first hit of the new one.
Either way, that's the method where you want to do your fetching of data.
There is no one location, you get a series of locations from CL, one cached and then others varying in accuracy over time, getting better (or worse) accuracy, taking anywhere from 1 second to 10 minutes.
CL will start by giving you a cached location, which may be good enough for your purposes. If it's not too old (<60 seconds) and reasonable accuracy, go ahead and use the cached location, it will be the fasted result. Otherwise you have to wait for a sufficiently good accuracy (you have to decide what is sufficient, look at .horizontalAccuracy).
If you insist on having the location before viewDidLoad is called (viewWillAppear would be a better place) then you have to hold off pushing that viewController until you have a sufficient location. How you do that depends on how that view controller is being loaded.
Here is what I would do. Load your view, and in your viewDidAppear, call your method to update location. I have been using a nice open source project on github called MBProgressHUD. It will display a variety of progress indicators on the screen (that will also block the user from leaving your view) while it finishes its work. It also gives a visual feedback to the user that your app hasn't stalled and is working.
You will still need to sort out your accuracy issues, but the progress view gives you time to load the view and keep the user engaged while you pull in what you need. And keeps your UI fluid.

Executing code in background

I have a application that periodically (via an NSTimer) asks for the users location using locationManager:startUpdatingLocation I want the locationManager to run in the background so have entered "UIBackgroundModes = location" in the info.plist file.
My question is I am not seeing the results I expected, am I right in thinking that when I press the home button the application delegate calls "applicationDidEnterBackground" but although locationManager is allowed to continue my NSTimer is getting suspended (and as a consequence its not calling startUpdatingLocation to periodically query the devices position). Any ideas / solutions would be much appreciated ...
Gary.
All NSTimers are invalidated when entering the background. You need check via the CLLocationManager for any changes.
Just keep the startUpdateLocation running, you delegate will receive any major changes of the location.
When running in the background, you will only receive location changes based on cell towers.
If you read the documentation for -applicationDidEnterBackground: you'll find that yes, your timers are invalidated. Furthermore, the iOS Application Programming Guide tells you exactly how to track location from the background.

Turning off the GPS updates when user hits the home button on iPhone

I have an application with four tabs. Two of the tabs use location updates and other two don't require GPS. I use following code to turn off the location updates when the view is about to disappear
(void)viewWillDisappear:(BOOL)animated {
[self.locationManager stopUpdatingLocation];
}
This seems to work when I change tabs. The puzzle is that when user hits the home button while in the tabs which do not require location information then GPS is turned off. However if the user hits the home button while in one of the tabs that is using location updates then the GPS is left turn on. I think it is because "viewWillDisappear" is never called when the user hits the home button.. Am I right in that assumption, any suggestion on how to fix this problem.
Soofi
Add the "UIBackgroundModes" key to your -Info.plist but don't specify any values, that should ensure location services are not used in the background.
well, unless you've specifically set up the app to have background services for gps, it won't continue running, and I'm guessing you have not done so, otherwise, you wouldn't be asking how to stop it...however, for completeness, just in case you really do want that, I think you want the applicationDidEnterBackground method

mkmapview.userslocation property set to 0,0 after allowing app to use current location

On the first time the user tries to use the current location the map.userslocation property has coordinates of 0,0. The next time I load the view containing the map the users location is always found.
I am setting the map.showsUserLocation property to YES on viewDidLoad and when the map loads on the screen the blue dot is there but when I try to get the coordinates with map.userlocation.coorinate they are 0,0.
The program flow goes
-(void) viewDidLoad:
1) set showUserLocation to YES
2) Set a timer to call a method 6 seconds later that grabs the users location from the map.userLocation property
-(void) getUsersLocation
1) print out the users location
This process works great after the first time I load the view, but the first time the view is laoded and the user has to grant permission to use their location the coordinates come back 0,0
Anybody have any idea why this happens and how I can work around it?
Thanks!
rather than arbitrarily waiting six seconds, you should be implementing CLLocationManagerDelegate and noticing when
locationManager:didUpdateToLocation:fromLocation:
is called to give you the first location update, which might take more or less time than that.
David is right, but I've noticed that I do sometimes get that method called with a location of 0,0. You should ignore any such calls, unless you think your app may be being used in the sea off the west coast of Africa.