如何在DelferredLocationUpdatesAvailable返回NO时通过ios高效地获取位置更新

如何在DelferredLocationUpdatesAvailable返回NO时通过ios高效地获取位置更新,ios,objective-c,cllocationmanager,Ios,Objective C,Cllocationmanager,我正在尝试推迟ios 11中的位置更新,以节省电源。默认值似乎是以尽可能快的速度更新(即每秒钟更新一次),所以我想推迟更新,或者做一些其他聪明的事情来制作一个节能的应用程序 实施CLLocationManager并进行如下设置时: _locationManager = [[CLLocationManager alloc] init]; _locationManager.delegate = _sharedInstance = [[LocationManager alloc] in

我正在尝试推迟ios 11中的位置更新,以节省电源。默认值似乎是以尽可能快的速度更新(即每秒钟更新一次),所以我想推迟更新,或者做一些其他聪明的事情来制作一个节能的应用程序

实施CLLocationManager并进行如下设置时:

    _locationManager = [[CLLocationManager alloc] init];
    _locationManager.delegate = _sharedInstance = [[LocationManager alloc] init];
    [_locationManager requestAlwaysAuthorization];
    _locationManager.allowsBackgroundLocationUpdates = true;
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    _locationManager.distanceFilter = 0;
    _locationManager.pausesLocationUpdatesAutomatically = NO;
    _locationManager.activityType = CLActivityTypeFitness; 
[CLLocationManager deferredLocationUpdatesAvailable]在didUpdateLocations中返回false,因此在尝试使用AllowDeferredLocationUpdatesUntiltTraveled方法延迟时出现错误11

这些问题(和)表明不再支持延迟位置更新


不管怎样,如果您希望每x(例如15)秒更新一次,达到最佳(即gps)精度,并且始终在后台工作/运行,那么您如何使ios定位应用程序节能呢?

这个答案可能有点错误,因为事实上,即使文档没有被删除,也不可能再使用deffering功能。但目的是每隔一段时间打开/关闭该位置,以避免一直打开该位置以节省电力

为了接近完全打开/关闭,可以在高精度和低精度之间切换,这肯定会节省电源。(通常使用500米的高精度

首先,以所需的时间间隔启动NSTimer,然后开始高精度更新。在didUpdateLocations中接收位置时,从高精度更改为低精度。NSTimer的回调请求新的高精度位置更新(即调用
setupHighAccurance
)。计时器因此设置高精度更新的频率。这也将在后台工作,因为位置服务仍在运行。如果停止更新,应用程序将在后台停止。当停止并立即再次启动位置管理器时,它将立即调用didUpdateLocation,但检查时间戳、loca可以缓冲缓冲缓冲

显示下面的一些代码片段以开始。生产代码将需要更多的筛选和测试:

@property (retain, nonatomic) NSTimer *atimer;

static BOOL _lowAccuracy;  

- (void)timerCallback {
    [self setupHighAccuracy];
}

- (void)setupTimer
{
    if(self.atimer != nil)
    {
        return;
    }

    UIApplication *app = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier bgTaskId =
    [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTaskId];
        bgTaskId = UIBackgroundTaskInvalid;
    }];

    dispatch_async( dispatch_get_main_queue(), ^{

                        self.atimer = [NSTimer scheduledTimerWithTimeInterval:15.0 // consider higher interval
                                    target:self
                                    selector:@selector(timerCallback)
                                    userInfo:nil
                                    repeats:YES];

                    }   

        [app endBackgroundTask:bgTaskId];
        bgTaskId = UIBackgroundTaskInvalid;
    });
}

- (void)setupHighAccuracy
{    
    if(_lowAccuracy)
    {        
        [_locationManager performSelectorOnMainThread:@selector(stopUpdatingLocation) withObject:nil waitUntilDone:YES];
        _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; // or kCLLocationAccuracyBest, tune yourself
        _locationManager.activityType = CLActivityTypeFitness;
        _locationManager.distanceFilter = 15; // or 0, tune yourself
        _lowAccuracy = false;
        [_locationManager performSelectorOnMainThread:@selector(startUpdatingLocation) withObject:nil waitUntilDone:YES];
    }
}

- (void)setupLowAccuracy
{    
    if(!_lowAccuracy)
    {
        s_initialized = true;            
        [_locationManager performSelectorOnMainThread:@selector(stopUpdatingLocation) withObject:nil waitUntilDone:YES];
        _locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
        _locationManager.activityType = CLActivityTypeFitness;
        _locationManager.distanceFilter = 3000;
        _lowAccuracy = true;
        [_locationManager performSelectorOnMainThread:@selector(startUpdatingLocation) withObject:nil waitUntilDone:YES];
    }
}

- (void)locationManager:(CLLocationManager *)manager
    didUpdateLocations:(NSArray *)locations
{
    CLLocation *location = locations.lastObject;
    if(!_lowAccuracy) {            
        // update system with location here
        [_locationManager.delegate setupLowAccuracy];
        self.s_lastLocation = location;
    }             
}

基本上,如果您想要基于GPS的连续定位(即高精度)定位然后您将使用大量的电源。消耗电源的是GPS接收器本身,而不是处理更新的CPU,我怀疑这就是为什么不再支持延迟位置更新的原因;这对于节省电源来说毫无意义。使用更少电源的唯一方法是使用不太准确的定位服务。@Paulw11,谢谢你的评论。每分钟一次的准确定位应该比每秒钟一次的更新消耗更少的能量,对吗?(那么他们为什么不干脆关掉GPS接收器,同时推迟或采用其他类似的方法呢?)任何人只要有工作循环GPS开/关作为节电替代品的经验?哪个回调将在后台运行以准备下一个工作循环?您可以节电:通过设置粗略的
距离过滤器
值。通过不要求过高的精度。通过正确设置
活动类型
并允许暂停更新。通过使用位置监视而不是后台更新。@matt,谢谢。通过测试,设置距离过滤器确实节省了电源。现在正式不推荐使用延迟位置(iOS 13).所以苹果承认它们不起作用。考虑到延迟更新不起作用,如果用户的设备应该在运行中,使用locationManager的distanceFilter值100/300不是一个好主意吗?@Roboris,是的,使用distanceFilter可能是一个好选择,只要不需要连续更新。记住r在这种情况下,由操作系统决定何时更新下一个位置。在某些情况下,定期更新新位置(带有时间戳)是很方便的。