When I start my application fresh, or resume after a long time, MKMapView's notion of the userLocation is wrong and shows me in the middle of the sea.
I am using the following code:
self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate;
[mapView setCenterCoordinate:self.mapView.userLocation.location.coordinate zoomLevel:ZOOM_LEVEL animated:YES];
Happens after a lengthy resume of the app or brand new start....
This is unfortunately a function of the GPS chip. It's not always on, so the data will usually be wrong for the first couple of moments. Your best bet would probably be to store the last position recorded by the app in NSUserDefaults, then wait for the precision to be where you want it to be before switching to live data, or else hide the MkMapView until the precision is where you want it to be, then display it at that point (you could show a loading screen in the interim)
When using CLLocationManager directly, you normally get a cached location in the first callback. It's normally a good location, although old. After that you quickly get additional callbacks giving better locations using wifi, cell tower (if available). If you have asked for < 1000m accuracy you will (after more seconds) get GPS triangulation.
None of those should be inaccurate enough to be in the middle of the ocean. I suspect that the this line of code:
is accessing the coordinate while
userLocation
orlocation
isnil
. IfuserLocation
orlocation
is nil, this will return 0 coordinates. The location of lat=0, lon=0 is in the Atlantic Ocean, off the coast of Africa. You could add a check oflocation
to make sure it is not nil before getting the coordinate from it, ie:You will also want to wait for callbacks to the MKMapViewDelegate
mapView:didUpdateUserLocation:
to know when there is a valid location available. Your implementation ofdidUpdateUserLocation:
should discard any location that has a horizontalAccuracy < 0 which indicates an invalid location.What I do here is-
If you need very accurate location, then put a check on accuracy as well and a timeout beyond which you can't tolerate waiting and use the less accurate fix.
Just as Jeremy Massel wrote you have to sort out the first bad positions on app start / continue. Found a great blog post a couple of months ago:
http://troybrant.net/blog/2010/02/detecting-bad-corelocation-data/
In my apps I used these methods:
First - it's good to have a default position (for example - application is about a city - then zoom in to show whole city) (on first - first app opening, when no data downloaded)
Second - if user has already used map - can store his coordinates, and show those (+ span(zoom) level) in case there are no other data available.
Third - in case of data:
1.) If database has already some coordinates - on first map opening (when application has been closed) - zoom out/in to show all pins on map.
2.) When still in map and just arrived updates (new locations or changed something), there are two possibilities :
2.1.) If user has not zoomed in to any location - map zooms in/out to show all locations.
2.2.) if user has zoomed in - locations are updated, but map doesnt zoom out
Ofcourse - then there are also some filter buttons (for example : search, user location, and some more - which filters locations, and zooms out/in to show filtered results)
How far off is it from your actual location? When an application just starts or resumes from a long period of time the user location is general always wrong to begin with. As the application runs it will get more and more accurate. There are methods for getting the accuracy of the user location in CLLocationManager, see what kind of values you get there.