在后台任务执行期间,如果用户杀死应用程序(已经处于后台模式)会发生什么?
想象一下:
该应用程序启动任务 X(具有 10 分钟的后台支持和必须调用的过期处理程序)。然后,应用程序进入后台,用户终止应用程序。
我对应用程序被杀死后任务 X 会发生什么感到困惑。它还有执行的后台时间吗?过期处理程序是否被调用?
在后台任务执行期间,如果用户杀死应用程序(已经处于后台模式)会发生什么?
想象一下:
该应用程序启动任务 X(具有 10 分钟的后台支持和必须调用的过期处理程序)。然后,应用程序进入后台,用户终止应用程序。
我对应用程序被杀死后任务 X 会发生什么感到困惑。它还有执行的后台时间吗?过期处理程序是否被调用?
如果应用程序“已经在后台”,则用户已经“关闭应用程序”!那么你的问题意味着什么?你已经进入了后台,如果你照常打电话beginBackgroundTaskWithExpirationHandler:
,事情就会正常进行。
你的意思是用户在后台强行杀死应用程序,通过召唤“最近的应用程序”界面并进入jiggy模式并从“最近的应用程序”界面删除应用程序?然后该应用程序被立即杀死;您没有收到任何通知,并且您正在做的任何事情都会被打断。
此外,过期处理程序块应该做的唯一事情就是调用endBackgroundTask:
。如果您被立即杀死,那么您无法拨打此电话的事实并不重要!
好的,这就是结果
在这种情况下,操作系统将向您的应用程序进程发送 SIGKILL 信号,并且不会调用 applicationWillTerminate 方法。
以下只是我对 Apple 文档、猜测工作和 Google 结果的解释。
在这种情况下,您的应用程序委托的以下方法将被调用
- (void)applicationWillTerminate:(UIApplication *)application
引用 Apple Docs
对于不支持后台执行或链接到 iOS 3.x 或更早版本的应用程序,当用户退出应用程序时始终调用此方法。对于支持后台执行的应用程序,当用户退出应用程序时通常不会调用此方法,因为在这种情况下应用程序只是移动到后台。但是,在应用程序在后台运行(未挂起)并且系统出于某种原因需要终止它的情况下,可能会调用此方法。
因此,您必须在 plist 文件中将 UIApplicationExitsOnSuspend 值设置为 YES,否则无法保证 applicationWillTerminate: 将被调用。这就是为什么文档可能使用的原因。
尽管我不确定,但我认为不会调用过期处理程序块。
这很容易测试,所以我刚刚(在运行 iOS 6.1.3 的 iPhone 4S 上)使用了我将在最后粘贴的代码,它在应用程序委托的applicationDidEnterBackground
方法中启动了一个后台任务。
结果令人惊讶。
当用户通过单击主页按钮退出应用程序,然后手动终止应用程序(通过双击主页,将事物置于 jiggy 模式并点击应用程序的关闭图标)时,会发生以下情况:
applicationWillTerminate
叫做。applicationWillTerminate
,无论后台任务还剩多少执行时间,后台执行都会终止。该应用程序已被杀死。然而..
如果您安排的事情applicationWillTerminate
在被调用后不会退出,如下面的代码所示,当手动终止应用程序时,会发生以下情况——至少在我的测试设置中是这样:
applicationWillTerminate
,直到该方法退出。这显然是一个错误——你不应该永远继续运行代码——而且我不会依赖它一直工作。但是那些一直在使用各种技巧来在后台播放音频以保持应用程序存活的人可能想要进行调查。如果其他人在不同的 iOS 版本/设备上尝试代码并获得相同的结果,我会很感兴趣。
我的测试项目中 AppDelegate.m 的代码:
//
// BTAppDelegate.m
// BackgroundTest
//
// Created by David Fearon on 07/05/2013.
// Copyright (c) 2013 David Fearon. All rights reserved.
//
#import "BTAppDelegate.h"
@implementation BTAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(@"application didFinishLaunchingWithOptions called");
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
NSLog(@"applicationWillResignActive: called");
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(@"applicationDidEnterBackground: called");
UIApplication* thisApp = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier __block task = [thisApp beginBackgroundTaskWithExpirationHandler:^{
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self printTimeRemaining];
while(YES) {
[NSThread sleepForTimeInterval:1.0];
[self printTimeRemaining];
}
//[thisApp endBackgroundTask:task];
});
}
-(void)printTimeRemaining{
NSLog(@"Background task time remaining: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSLog(@"applicationWillEnterForeground: called");
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(@"applicationDidBecomeActive: called");
}
- (void)applicationWillTerminate:(UIApplication *)application
{
NSLog(@"applicationWillTerminate: called");
while(YES) {
[NSThread sleepForTimeInterval:1.0];
NSLog(@"Still executing code in applicationWillTerminate.");
}
}
@end