设备锁定时后台任务停止?
Background task stopping when device locked?
我有一个计时器 运行 当设备进入后台时我想检查我服务中的少量数据。我在 app delegate
的 applicationDidEnterBackground 方法中使用了以下代码
UIApplication *app = [UIApplication sharedApplication];
//create new uiBackgroundTask
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
//and create new timer with async call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//run function methodRunAfterBackground
NSString *server = [variableStore sharedGlobalData].server;
NSLog(@"%@",server);
if([server isEqual:@"_DEV"]){
arrivalsTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(getArrivals) userInfo:nil repeats:YES];
}
else {
arrivalsTimer = [NSTimer scheduledTimerWithTimeInterval:300 target:self selector:@selector(getArrivals) userInfo:nil repeats:YES];
}
[[NSRunLoop currentRunLoop] addTimer:arrivalsTimer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
这绝对没问题,直到设备自动锁定,然后计时器停止计时。关于如何阻止这种情况发生的任何建议?默认的实时时间是 5 分钟,因此大多数设备会在这个甚至滴答一次之前很久就被锁定。
谢谢
一些观察:
正如 H 先生所指出的,beginBackgroundTaskWithExpirationHandler
在现代 iOS 版本中只给你 30 秒(之前是 3 分钟)。因此,尝试在五分钟内启动计时器是行不通的。
您可以使用[[UIApplication sharedApplication] backgroundTimeRemaining]
查询剩余时间。
当设备锁定时,后台任务会继续。您不应该看到应用终止。如果用户通过“双击主页按钮并在任务切换器屏幕上向上滑动”手动终止应用程序,这将终止后台任务,而不是简单地锁定设备。
关于计时器的几点评论:
代码正在将计时器添加到后台队列。这通常是没有必要的。仅仅因为应用程序处于后台状态,您仍然可以继续使用主 运行 循环来处理计时器等。
因此,只需从主线程调用 scheduledTimerWithTimeInterval
即可。除非绝对必要,否则用 运行 循环耗尽 GCD 工作线程是没有意义的(即便如此,我可能会创建自己的线程并向其添加 运行 循环)。
顺便说一下,如果绝对有必要在某些后台调度队列上安排计时器,那么使用调度计时器可能更容易。它完全消除了 运行 循环要求。
顺便说一句,scheduledTimerWithTimeInterval
和 addTimer
一起使用是不合适的。您调用 scheduledTimerWithTimeInterval
创建一个计时器并将其添加到当前 运行 循环。如果要将其添加到另一个 运行 循环,请使用 timerWithTimeInterval
然后调用 addTimer
。
我有一个计时器 运行 当设备进入后台时我想检查我服务中的少量数据。我在 app delegate
的 applicationDidEnterBackground 方法中使用了以下代码 UIApplication *app = [UIApplication sharedApplication];
//create new uiBackgroundTask
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
//and create new timer with async call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//run function methodRunAfterBackground
NSString *server = [variableStore sharedGlobalData].server;
NSLog(@"%@",server);
if([server isEqual:@"_DEV"]){
arrivalsTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(getArrivals) userInfo:nil repeats:YES];
}
else {
arrivalsTimer = [NSTimer scheduledTimerWithTimeInterval:300 target:self selector:@selector(getArrivals) userInfo:nil repeats:YES];
}
[[NSRunLoop currentRunLoop] addTimer:arrivalsTimer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
这绝对没问题,直到设备自动锁定,然后计时器停止计时。关于如何阻止这种情况发生的任何建议?默认的实时时间是 5 分钟,因此大多数设备会在这个甚至滴答一次之前很久就被锁定。
谢谢
一些观察:
正如 H 先生所指出的,
beginBackgroundTaskWithExpirationHandler
在现代 iOS 版本中只给你 30 秒(之前是 3 分钟)。因此,尝试在五分钟内启动计时器是行不通的。您可以使用
[[UIApplication sharedApplication] backgroundTimeRemaining]
查询剩余时间。当设备锁定时,后台任务会继续。您不应该看到应用终止。如果用户通过“双击主页按钮并在任务切换器屏幕上向上滑动”手动终止应用程序,这将终止后台任务,而不是简单地锁定设备。
关于计时器的几点评论:
代码正在将计时器添加到后台队列。这通常是没有必要的。仅仅因为应用程序处于后台状态,您仍然可以继续使用主 运行 循环来处理计时器等。
因此,只需从主线程调用
scheduledTimerWithTimeInterval
即可。除非绝对必要,否则用 运行 循环耗尽 GCD 工作线程是没有意义的(即便如此,我可能会创建自己的线程并向其添加 运行 循环)。顺便说一下,如果绝对有必要在某些后台调度队列上安排计时器,那么使用调度计时器可能更容易。它完全消除了 运行 循环要求。
顺便说一句,
scheduledTimerWithTimeInterval
和addTimer
一起使用是不合适的。您调用scheduledTimerWithTimeInterval
创建一个计时器并将其添加到当前 运行 循环。如果要将其添加到另一个 运行 循环,请使用timerWithTimeInterval
然后调用addTimer
。