首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么beginBackgroundTaskWithExpirationHandler允许NSTimer在后台运行?

为什么beginBackgroundTaskWithExpirationHandler允许NSTimer在后台运行?
EN

Stack Overflow用户
提问于 2015-03-26 16:02:19
回答 2查看 1.1K关注 0票数 1

我知道在类似的话题上有很多问题,但我认为没有人能解决这个问题(尽管我很高兴被证明是错的!)

首先是一些背景,我已经开发了一个应用程序来监控用户在后台的位置,这是很好的工作,但电池使用率很高。为了改进这一点,我的目标是每隔x分钟就‘醒来’,打电话给startUpdatingLocation得到一个位置,然后打电话给stopUpdatingLocation

请考虑我为测试而收集的以下示例:

代码语言:javascript
运行
复制
@interface ViewController ()
@property (strong, nonatomic) NSTimer *backgroundTimer;
@property (strong, nonatomic) CLLocationManager *locationManager;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // Add observers to monitor background / foreground transitions
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];

    _locationManager = [[CLLocationManager alloc] init];
    [_locationManager requestAlwaysAuthorization];
    _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
    _locationManager.delegate = self;
    _locationManager.distanceFilter=100;
    [_locationManager startUpdatingLocation];


    NSTimeInterval time = 60.0;
    _backgroundTimer =[NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(startLocationManager) userInfo:nil repeats:YES];

}

-(void)applicationEnterBackground{
    NSLog(@"Entering background");
}

-(void)applicationEnterForeground{
    NSLog(@"Entering foreground");
}

-(void)startLocationManager{
    NSLog(@"Timer fired, starting location update");
    [_locationManager startUpdatingLocation];
}

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    NSLog(@"New location received");
    [_locationManager stopUpdatingLocation];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];    
}
@end

正如预期的那样,当应用程序进入后台时,CLLocationManager不会更新位置,因此NSTimer会暂停,直到应用程序进入前台。

一些类似的问题询问了如何让NSTimers在后台运行,以及beginBackgroundTaskWithExpirationHandler的使用,因此我在NSTimer启动之前将其添加到viewDidLoad方法中。

代码语言:javascript
运行
复制
UIBackgroundTaskIdentifier bgTask = 0;
UIApplication *app = [UIApplication sharedApplication];
NSLog(@"Beginning background task");
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    NSLog(@"Background task expired");
    [app endBackgroundTask:bgTask];
}];
NSLog(@"bgTask=%d", bgTask);

通过短期测试(是否长期有效还有待证实),这似乎解决了这个问题,但我不明白为什么。

如果您查看下面的日志输出,您可以看到,当应用程序进入后台时,当beginBackgroundTaskWithExpirationHandler继续运行时,调用NSTimer就达到了预期的目标:

代码语言:javascript
运行
复制
2015-03-26 15:45:38.643 TestBackgroundLocation[1046:1557637] Beginning background task
2015-03-26 15:45:38.645 TestBackgroundLocation[1046:1557637] bgTask=1
2015-03-26 15:45:38.703 TestBackgroundLocation[1046:1557637] New location received
2015-03-26 15:45:46.459 TestBackgroundLocation[1046:1557637] Entering background
2015-03-26 15:46:38.682 TestBackgroundLocation[1046:1557637] Timer fired, starting location update
2015-03-26 15:46:38.697 TestBackgroundLocation[1046:1557637] New location received
2015-03-26 15:47:38.666 TestBackgroundLocation[1046:1557637] Timer fired, starting location update
2015-03-26 15:47:38.677 TestBackgroundLocation[1046:1557637] New location received
2015-03-26 15:48:38.690 TestBackgroundLocation[1046:1557637] Timer fired, starting location update
2015-03-26 15:48:38.705 TestBackgroundLocation[1046:1557637] New location received
2015-03-26 15:48:42.357 TestBackgroundLocation[1046:1557637] Background task expired
2015-03-26 15:49:38.733 TestBackgroundLocation[1046:1557637] Timer fired, starting location update
2015-03-26 15:49:38.748 TestBackgroundLocation[1046:1557637] New location received
2015-03-26 15:50:38.721 TestBackgroundLocation[1046:1557637] Timer fired, starting location update
2015-03-26 15:50:38.735 TestBackgroundLocation[1046:1557637] New location received
2015-03-26 15:50:44.361 TestBackgroundLocation[1046:1557637] Entering foreground

从这一点上,您可以看到背景任务在大约3分钟后如预期的那样过期,但是在此之后,NSTimer将继续运行。

这是预期的行为吗?我将运行更多的测试,看看这个解决方案在长期内是否有效,但我不禁觉得我在使用后台任务时遗漏了什么?

EN

Stack Overflow用户

发布于 2015-03-27 12:31:42

有一个选项可以将后台任务用于长期运行的任务,然后iOS不支持执行。

根据后台执行文档,要使用它,应该将UIBackgroundModes键添加到Info.plist中,并带有值位置(用于位置更新)。还有另一个原因:

实现长期运行的任务。

实现这些服务的应用程序必须声明它们支持的服务,并使用系统框架来实现这些服务的相关方面。声明服务可以让系统知道您使用的是哪些服务,但在某些情况下,实际上是系统框架阻止您的应用程序被挂起。

可能只需初始化CLLocationManager即可使后台任务不被挂起。

票数 0
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29283328

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档