7

我有一个MKMapView应该使用自定义视图(而不是蓝点)来跟踪用户的位置。为了用这个视图代替蓝点,我这样返回它:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    if (annotation == [mapView userLocation])
    {
        return userLocationView;
    }
}

要初始化跟踪,我调用

[mapView setShowsUserLocation: YES];
[mapView setUserTrackingMode: MKUserTrackingModeFollow animated: NO];
[mapView setDelegate: self];

正如所料,-mapView:didUpdateUserLocation:在应用加载时被调用一次。-mapView:viewForAnnotation:不幸的是,除非我更改为具有以下实现,否则它再也不会被调用:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    if (annotation == [mapView userLocation])
    {
        return nil;
    }
}

通过这些更改,地图会加载蓝点作为用户位置的指示符,并-mapView:didUpdateUserLocation:像预期的那样频繁调用。

是否有某种互斥性来跟踪用户的位置并拥有自定义的用户位置视图?我怎样才能使两者都发生?

来源

这个项目演示了这个问题。https://dl.dropbox.com/u/2338382/MapKitFuckery.zip

漏洞

这很可能是一个错误,我已将其归档为雷达。在此期间,接受的答案应该证明是足够的。然而,值得注意的是,我不得不完全放弃[mapView userLocation]and [mapView showsUserLocation],转而支持简单的自定义注释和CLLocationManager.

4

2 回答 2

11

与其依赖地图视图的位置更新,不如启动 a CLLocationManager,设置它delegate并等待-locationManager:didUpdateToLocation:fromLocation:(在 iOS 5 及更低版本中)或-locationManager:didUpdateLocations:(iOS 6)。与使用地图视图的委托方法相比,您将获得更可靠、更丰富的信息。你可能知道如何做到这一点,但这里是:

#import <CoreLocation/CoreLocation.h>

- (void)viewWillAppear:(BOOL)animated
{
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [self.locationManager startUpdatingLocation];
}

// Deprecated in iOS 6
- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation
{

    // Check the age of the newLocation isn't too long ago using newLocation.timestamp

    // Set the map dot using newLocation.coordinate

    // Set an MKCircle to represent accuracy using newLocation.horizontalAccuracy
}

正如你所说,我查看了进入 mapView 委托的委托调用,并返回除了nil停止调用之外的任何内容。-mapView:didUpdateUserLocation:以下是按到达顺序的呼叫:

 - (void)mapViewWillStartLocatingUser:(MKMapView *)mapView
 - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation
 - (void)mapViewWillStartLoadingMap:(MKMapView *)mapView
 - (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error

大概是MKUserLocation对象,而不是MKMapView负责通过更新调用调用委托的对象。如果您检查 和 的状态showsUserLocationmapView.userLocation它们看起来都很好:

NSLog(@"%d %@", mapView.showsUserLocation, mapView.userLocation);

返回1一个非零对象 ( 1 <MKUserLocation: 0x1e02e580>)。也许mapView查询其userLocation对象以获取当前位置,然后将其发送给委托。如果该对象已经消失,它将无法工作。

这有点奇怪,但就像我说的,你会从 a 的更新中得到更好CLLocationManager的更新。

于 2012-11-14T00:17:38.640 回答
1

一个老问题,我想以自己的方式回答。我遇到了一个类似的问题。当我的 MapView 的 ViewController/Screen 被加载并且 mapView 检索到用户位置时,我只需要进行 Web 服务调用,将用户位置作为 GET 参数传递。在委托方法 didUpdateUserLocation 中调用 Web 服务是有意义的。我首先没有注意到错误的行为,因为事情似乎工作正常,但由于某些原因,有时在打开 mapView 屏幕时,会显示用户蓝点,但地图不会“放大”,也没有调用 didUpdateUserLocation 和我的内部显然是网络服务调用。盯着屏幕几秒钟后,地图将“放大”并调用 didUpdateUserLocation/web 服务。我想的一些小故障,没有大碍。现在我的注重细节的开发人员的头脑仍然感到沮丧,经过几周的思考,我决定对此采取行动。Stackoverflow 并没有立即给我答案,但仍然为我指明了正确的方向。罪魁祸首是:调用顺序!令人抓狂,但一旦我弄清楚事情就完全有意义了。我知道为了看到蓝点并获取用户位置,我必须告诉 mapView 这样做。因此,作为一个 Interface Builder 爱好者,我在 IB 中为我的 mapView 进行了正确设置,即我选中了框:“用户位置”,很简单。然后仔细阅读 mapView 文档,我意识到我的 ViewController 需要符合 MKMapViewDelegate,完成交易。正如我所说,一切似乎都正常,蓝点会立即显示,但有时会显示“https://stackoverflow.com/a/37407955),事情变得清晰起来。就我而言,由于使用了 IB,因此调用顺序如下:

  1. 在 IB 中选中的用户位置复选框
  2. 在 viewDidLoad 中,调用:mapView.delegate = self

然而,这里是调用顺序应该是这样的:

  1. 未在 IB 中选中用户位置复选框(这很重要)
  2. mapView.delegate = self
  3. mapView.showsUserLocation = true

这改变了一切。mapView 有时会立即放大,有时会在几秒钟后放大,现在 mapView 会在屏幕打开时立即放大,并调用 didUpdateUserLocation/web 服务。

现在再谈一谈为什么,它仍然“有时”有效。这仅仅是因为我的 iPhone 的位置有时会在地图屏幕加载后立即更新,有时不会:-)。我不得不说,除了我上面提到的 stackoverflow 帖子之外,帮助我的还有在模拟器中测试我的应用程序,因为我需要使用具有明显静态位置坐标的 gpx 文件,我描述的不可预测的行为是系统的。

因此,尽管我很喜欢 Interface Builder,但我可能不得不重新考虑这种爱是多么无条件。

PS:我知道这篇文章很旧,我的回答与@Patrick Perini 的问题并不完全相关,但我希望它对其他人有所帮助,并且它可能会回答@Patrick Perini 的结论,即错误不是错误的事实。感谢您阅读这篇博文 :-)

于 2017-11-15T15:28:18.737 回答