首先介绍一下iOS应用运行过程中会经历的5种状态:
Not Running:非运行状态
Inactive:前台非活动状态
Active:前台活动状态
Background:后台状态
Suspended:挂起状态
在应用状态迁移过程中回调的方法有以下几种:
application:didFinishLaunchingWithOptions:应用启动并进行初始化时
applicationDidBecomeActive:应用进入前台并处于活动状态时
applicationWillResignActive:应用从活动状态进入到非活动状态时
applicationDidEnterBackground:应用进入后台时
applicationWillEnterForeground:应用进入到前台,但还没有处于活动状态时
applicationWillTerminate:应用被终止时
本文主要描述应用的后台运行。当应用在前台运行时,点击Home键,根据应用属性文件中的Application does not run in background的值(Yes/No),此时该应用将分两种情况执行,经历的状态也有一点区别。
(1) 应用可以在后台运行
Active --> Inactive --> Background --> Suspended
(2) 应用不可以在后台运行
Active --> Inactive --> Background --> Suspended --> Not Running
我们知道,应用进入后台时,会调用applicationDidEnterBackground:方法,注意:不要在 applicationDidEnterBackground: 方法中执行耗时较长的任务,否则iOS系统可能直接从内存中删除该应用。另外,对于多线程任务,当应用进入后台时,如果该任务还没有执行完成,应用进入后台时该任务会被暂停。
为了请求更多的后台运行时间,可以调用 UIApplication 对象的 beginBackgroundTaskWithExpiration Handler: 方法。
首先使用默认通知中心监听UIApplicationDidEnterBackgroundNotification(应用进入后台通知),然后调用enterBack:方法。
- (void)viewDidLoad
{
[super viewDidLoad];
// 使用默认通知中心监听应用转入后台的过程
// 应用转入后台时会向通知中心发送UIApplicationDidEnterBackgroundNotification
// 从而激发enterBack:方法
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(enterBack:)
name:UIApplicationDidEnterBackgroundNotification
object:[UIApplication sharedApplication]];
}
然后在enterBack:方法中调用 UIApplication 对象的 beginBackgroundTaskWithExpiration Handler: 方法获取更多的后台运行时间,并调用 dispatch_async() 方法将指定代码块(需要在后台执行的任务)提交给后台执行,后台任务完成或超时后都要调用 UIApplication 对象的 endBackgroundTask: 方法来结束后台任务。
- (void) enterBack:(NSNotification*)notification
{
UIApplication* app = [UIApplication sharedApplication];
// 定义一个UIBackgroundTaskIdentifier类型(本质就是NSUInteger)的变量,
// 该变量将作为后台任务的标示符
__block UIBackgroundTaskIdentifier backTaskId;
/* beginBackgroundTaskWithExpirationHandler: 方法默认请求额外获取10分钟的后台时间 */
backTaskId = [app beginBackgroundTaskWithExpirationHandler:^
{
NSLog(@"===在额外申请的10分钟内依然没有完成任务===");
// 结束后台任务
[app endBackgroundTask:backTaskId];
}];
if(backTaskId == UIBackgroundTaskInvalid)
{
NSLog(@"===iOS版本不支持后台运行,后台任务启动失败===");
return;
}
// 将代码块以异步方式提交给系统的全局并发队列
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
, ^{
NSLog(@"===额外申请的后台任务时间为:%f==="
, app.backgroundTimeRemaining);
// 其他内存清理的代码也可在此处完成
for(int i = 0 ; i < 100 ; i ++)
{
NSLog(@"下载任务完成了%d%%" , i );
// 暂停10秒模拟正在执行后台下载
[NSThread sleepForTimeInterval:1];
}
NSLog(@"===剩余的后台任务时间为:%f==="
, app.backgroundTimeRemaining);
// 结束后台任务
[app endBackgroundTask:backTaskId];
});
}
通过 beginBackgroundTaskWithExpirationHandler: 方法来请求更多的后台运行时间,当该应用的后台时间减少到0时,将会调用 handler 代码块。
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler
如果该应用不能在后台执行,则会返回 UIBackgroundTaskInvalid;否则会返回后台任务的标识符,然后将该标识符传给
- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier 方法,用来结束任务。