MKMapView的用户位置在启动或恢复时错误
当我重新启动我的应用程序或在很长一段时间后恢复时,MKMapView 的 userLocation 概念是错误的,并显示我在海中央。
我正在使用以下代码:
self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate;
[mapView setCenterCoordinate:self.mapView.userLocation.location.coordinate zoomLevel:ZOOM_LEVEL animated:YES];
在应用程序长时间恢复或全新启动后发生......
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....
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
这是预期的行为:iPhone 并不总是使用 GPS 跟踪用户位置(这会消耗大量电池)。因此,一旦显示地图,
MKMapView
实例就会显示它所知道的最后一个“最佳”用户位置,然后通过激活跟踪来提高准确性(这是一个无缝的过程,您不需要必须关心它)。您可以通过实现
MKMapViewDelegate
协议来监控MKMapView
何时更新地图上的用户位置。只需实现:(来自苹果文档的更多信息 此处 )
我的示例中的上述代码检查地图视图当前显示的位置的准确性并做出相应的反应。
[编辑]
如果一开始在海中央显示用户位置确实让您感到困扰,您可以隐藏用户位置,直到获得足够准确/新鲜的位置。
为此,请首先将
MKMapView
的showsUserLocation
属性设置为NO
,直到获得足够准确的位置(感谢之前的委托回调),然后将其设置为YES
。通过这样做,您将避免显示不准确或太旧而无法显示的位置(
CLLocation
中有一个timestamp
属性来检查它是否是旧位置或不)注意:您不必必须在您这边创建一个
CLLocationManager
实例,MKMapView在内部创建一个实例并发布通过此委托选择器接收的位置.That's the expected behavior : the user location isn't always tracked by the iPhone using GPS (it would consume to much battery). So as soon as the map is displayed, the
MKMapView
instance shows the last 'best' user position it knows and then, improves the accuracy by activating the tracking (this is a seamless process, you don't have to care about it) .You can monitor when the
MKMapView
updates the user location on the map by implementing theMKMapViewDelegate
protocol. Just implement :(More info from the apple documentation here )
The code above in my example checks the accuracy of the position currently being displayed by the mapView and reacts accordingly.
[EDIT]
If showing the user location in the middle of the sea at first really bother you, you can you hide the user location until you get a location that is accurate/fresh enough.
To do so, set the
showsUserLocation
property of theMKMapView
toNO
at first until you get an accurate enough location (thanks to the previous delegate callback) and then set it toYES
.By doing you, you will avoid displaying a location that is not accurate or too old to be diplayed (there is a
timestamp
property in theCLLocation
to check wether it's an old location or not)N.B:You don't have to create a
CLLocationManager
instance on your side, the MKMapView creates one internally and publish locations it receives via this delegate selector.直接使用 CLLocationManager 时,通常会在第一个回调中获取缓存位置。虽然很旧,但通常位置很好。之后,您很快就会收到额外的回调,使用 wifi、手机信号塔(如果有)提供更好的位置。如果您要求< 1000m 精度,您将(更多秒后)获得 GPS 三角测量。
这些都不应该准确到足以位于海洋中央。我怀疑这行代码:
正在访问坐标,而
userLocation
或location
为nil
。如果userLocation
或location
为 nil,则将返回 0 坐标。 lat=0、lon=0 的位置位于大西洋、非洲海岸附近。您可以添加对location
的检查,以确保在从中获取坐标之前它不为零,即:您还需要等待对 MKMapViewDelegate
mapView:didUpdateUserLocation:
了解何时存在是可用的有效位置。您的didUpdateUserLocation:
实现应丢弃任何具有 水平精度 < 0 表示无效位置。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.不幸的是,这是 GPS 芯片的功能。它并不总是处于开启状态,因此在最初的几分钟内数据通常会是错误的。您最好的选择可能是将应用程序记录的最后位置存储在 NSUserDefaults 中,然后等待精度达到您想要的位置,然后再切换到实时数据,或者隐藏 MkMapView 直到精度达到您想要的位置是,然后在此时显示它(您可以在此期间显示加载屏幕)
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)
正如 Jeremy Massel 所写,您必须解决应用程序启动/继续时的第一个不好的位置。几个月前发现了一篇很棒的博客文章:
http://troybrant .net/blog/2010/02/Detecting-bad-corelocation-data/
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/
我在这里所做的是 -
如果您需要非常准确的位置,请检查准确性以及一个超时,超过这个超时,您将无法忍受等待并使用不太准确的修复。
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.
距离您的实际位置有多远?当应用程序刚刚启动或从很长一段时间恢复时,用户位置通常总是错误的。随着应用程序的运行,它会变得越来越准确。 CLLocationManager 中有一些方法可以获取用户位置的准确性,看看你能得到什么样的值。
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.
在我的应用程序中,我使用了这些方法:
首先 - 最好有一个默认位置(例如 - 应用程序是关于一个城市的 - 然后放大以显示整个城市)(首先 - 第一个应用程序打开,没有下载数据时)
第二 -如果用户已经使用过地图 - 可以存储他的坐标,并显示这些坐标(+跨度(缩放)级别),以防没有其他可用数据。
第三 - 如果是数据:
1.) 如果数据库已经有一些坐标 - 第一次打开地图时(当应用程序关闭时) - 缩小/缩小以显示地图上的所有图钉。
2.) 当仍在地图中且刚刚到达更新(新位置或更改某些内容)时,有两种可能性:
2.1.) 如果用户尚未放大到任何位置- 地图放大/缩小以显示所有位置。
2.2.) 如果用户放大了 - 位置已更新,但地图没有缩小
当然 - 然后还有一些过滤按钮(例如:搜索、用户位置等 - 可以过滤位置) ,并缩小/放大以显示过滤结果)
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)