[iOS][Background][CLLocationManager]地图精度不好

Posted

技术标签:

【中文标题】[iOS][Background][CLLocationManager]地图精度不好【英文标题】:[iOS][Background][CLLocationManager]Bad map accuracy 【发布时间】:2013-05-05 16:19:29 【问题描述】:

我正在开发一个应用程序,旨在在地图上显示 iPhone 在活动期间的位置(添加注释并在它们之间画线)。

为此,我使用位置管理器获取新位置并通知 MapDisplayViewController。与模拟器一起使用时,我得到了很好的结果,你可以在这里看到http://www.youtube.com/watch?v=ESLIYSU_Mqw,但是使用 iPhone,我得到了奇怪的结果,比如 200 米错误。

我还使用 MKMapView 来显示设备位置。通过这些设置(下一个代码块)我得到了http://grab.by/mgUU。

如果我显示用户位置我得到不同的结果,这是正常的吗?

- (void)setupMap 
self.mapView.delegate = self;

[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
[self.mapView setUserInteractionEnabled:NO];

[self.mapView setShowsUserLocation:NO];
[self.mapView setZoomEnabled:NO];
[self.waitingView start];


这里是真机截图:

后台:http://grab.by/mgN2 没有背景:http://grab.by/mgNc

编辑:区别来自我在这两种情况下使用的两种不同的获取设备当前位置的方法:

应用处于活动状态时来自 mapView 的句柄 应用在后台时位置管理器的句柄

混合使用两个位置系统是否是个好主意?

我也测试了这个解决方案CLLocationManager and accuracy issues - any experiences?,但我得到了相同的结果。

谢谢 ;)

位置管理器的设置:

- (void)setup 
self.locationManager = [CLLocationManager new];
self.locationManager.delegate = self;

self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.isUpdatingLocation = NO;

通知:在后台添加位置时:

- (void)doUpdateWithLocation:(CLLocation *)location 

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^

    [self beginBackgroundUpdateTask];


    NSLog(@"%s do update in background %@", __PRETTY_FUNCTION__, location);

    if (self.userLocationFound == NO && self.isUpdatingLocation == YES) 
        self.startCoordinate = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);

        self.userLocationFound = YES;
    
    else if (self.isUpdatingLocation) 
        static int distance;

        ABGPSPosition *position = [[ABGPSPosition alloc] init];
        position.startPoint = MKMapPointForCoordinate(self.startCoordinate);
        position.endPoint = MKMapPointForCoordinate(location.coordinate);

        //INFO: Get the distance between this new point and the previous point.
        CLLocationDistance metersApart = MKMetersBetweenMapPoints(position.startPoint, position.endPoint);
        if (metersApart > MINIMUM_DELTA_METERS) 
            MKMapPoint points[2] = position.startPoint, position.endPoint;


            distance += metersApart;
            NSLog(@"%s - %d", __PRETTY_FUNCTION__, distance);

            NSInteger count = [self.measurementArray count];
            [self willChange:NSKeyValueChangeInsertion
             valuesAtIndexes:[NSIndexSet indexSetWithIndex:count] forKey: @"measurementArray"];
            [self.measurementArray insertObject:location atIndex:count];
            [self didChange:NSKeyValueChangeInsertion
            valuesAtIndexes:[NSIndexSet indexSetWithIndex:count] forKey: @"measurementArray"];


            self.startCoordinate = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
        

    

        [self endBackgroundUpdateTask];
    );

MapDisplayViewController 获取新位置:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context


if ([keyPath isEqualToString:keyPathMeasurementArray]) 
    if ([change[NSKeyValueChangeKindKey] intValue] == NSKeyValueChangeInsertion)       

        NSIndexSet *insertedIndexSet = change[NSKeyValueChangeIndexesKey];

        [insertedIndexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) 

            CLLocation *location = self.locationManager.measurementArray[idx];

            MKUserLocation *userLocation = [[MKUserLocation alloc] init];
            [userLocation setCoordinate:location.coordinate];
            NSLog(@"%s - didUpdateUserLocation", __PRETTY_FUNCTION__);

                [self.locationBackgroundList addObject:userLocation];
                NSLog(@"%s | %@", __PRETTY_FUNCTION__, self.locationBackgroundList);                
        ];
    

else 
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];


MapDisplayViewController 为新地图视图添加注解:

- (void)handleAddLocations 
NSLog(@"%s | %@", __PRETTY_FUNCTION__, self.locationBackgroundList);

if ([self.locationBackgroundList count] > 0) 
    for (MKUserLocation *backgroundUserLocation in self.locationBackgroundList) 

        
            LocAnnotation* annotation = [[LocAnnotation alloc] initWithCoordinate:backgroundUserLocation.coordinate];
            NSLog(@"%s %@", __PRETTY_FUNCTION__, [backgroundUserLocation description]);



            [self.mapView addAnnotation:annotation];
        
        [self mapView:self.mapView didUpdateUserLocation:backgroundUserLocation];
    

    NSString *message = [NSString stringWithFormat:@"%s | Annotation number: %d", __PRETTY_FUNCTION__, [self.locationBackgroundList count]];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Debug" message:message delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
    [alert show];

    [self.locationBackgroundList removeAllObjects];
    self.locationBackgroundList = [[NSMutableArray alloc] init];
    

【问题讨论】:

【参考方案1】:

修正了您只能使用一种方法通过 CLLocationManagerMapView 来定位您的设备。 ;)

【讨论】:

以上是关于[iOS][Background][CLLocationManager]地图精度不好的主要内容,如果未能解决你的问题,请参考以下文章

是否有 iOS API 用于处理地图上的区域并计算交叉点、面积等?

[iOS][Background][CLLocationManager]地图精度不好

ios background transfer service怎么用

React-Native IOS:Background-Timer 不在后台运行

Cordova Background Fetcher 插件不适用于 iOS

ios移动端部分手机不支持background-attachment: fixed 的解决办法