后台运行探索与解析

iOS 后台运行


当用户没有主动的使用你的应用程序时,系统会将它转换为后台运行状态。对于大多说应用程序来说,后台运行状态只是应用程序在被系统挂起前的一个阶段。挂起应用程序是一个改善电池寿命并让系统为前台应用程序释放重要资源的方式。

大多数应用程序都能很容易的挂起,但是拥有合理的理由在后台继续运行的应用程序也是有的。一个远足应用程序想要随着时间来定位用户的位置,让它能够在地图上显示用户的运动进程。一个音频应用程序可能需要在屏幕锁定时继续播放音乐。其它的应用程序可能想要在后台下载内容以便能够减少将内容呈献给用户的延迟。当你发现你的应用程序需要保持在后台继续运行的时候,iOS系统能够帮助你有效率的且尽可能少地占用系统资源的完成这个目的。

iOS提供的技术分为三类:

  • 在前台开始短任务的应用程序可以在进入后台状态时向系统请求完成这个任务的额外时间。
  • 在前台启动下载的应用程序可以将这些下载的管理移交给系统,从而允许在下载过程中暂停或终止该应用。
  • 需要在后台运行以支持特定类型任务的应用程序可以声明对一个或多个后台执行模式的支持。

尽可能避免在后台执行任何任务除非这样做能全面的提升用户的体验。应用程序可能会因为启动了另一个应用程序,锁定了屏幕或现在不使用它而被转入后台。在这些情况下,用户都表明你的应用程序现在不需要做任何有意义的工作。在这种情况下继续运行只会浪费设备的电量并可能导致用户强制的完全退出你的应用程序。所以你应该审慎的考虑在后台运行应用程序。

执行有限长度的任务

被转入后台的应用程序期待尽可能快的进入非活动状态以便它们能够被系统挂起。如果你的应用程序正在执行某个任务而且完成这个任务还需要一些时间的话,你可用调用 UIApplicationbeginBackgroundTaskWithName:expirationHandler:beginBackgroundTaskWithExpirationHandler:方法来请求一些额外的执行时间。调用这两个方法的任一个都会暂时的推迟你的应用程序被挂起,从而为完成你正在进行的任务赢得一些额外的时间。一旦你的应用程序完成了任务,你必须调用endBackgroundTask:方法让系统知道你的应用程序已经完成了任务,可以被挂起了。

每个调用beginBackgroundTaskWithName:expirationHandler:beginBackgroundTaskWithExpirationHandler: 方法的应用程序都会生成一个与相应的任务相关的标记。当你的应用程序完成任务时,它必须以这个标记来调用 endBackgroundTask:方法告知系统任务已经完成。调用 endBackgroundTask:方法失败会导致你的应用程序被终止。如果你在启动任务的时候提供了一个完成处理模块,系统会调用这个模块并给你最后一次结束任务避免程序被终止的机会。

你不需要一直到等到应用程序进入后台才指定后台任务。一个更有用的设计是在开始任务之前调用beginBackgroundTaskWithName:expirationHandler:beginBackgroundTaskWithExpirationHandler:方法,一旦完成就调用endBackgroundTask:方法.

下面的的代码展示了当你的应用程序进入后台时如何开始一个长时运行的任务。在这个例子中,开始后台任务的请求包含了一个完成处理模块以防这个任务耗时太长。这个任务稍后会被提交到一个异步执行的队列中以便applicationDidEnterBackground:方法能够正常返回。blocks的使用简化了维护一些重要变量引用所需要的代码。bgTask变量是指向存储当前任务标识符的指针的类的成员变量,它在调用这个方法之前被初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void)applicationDidEnterBackground:(UIApplication *)application {
bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];

// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

// Do the work associated with the task, preferably in chunks.

[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}

注意: 你总是要在开始一个任务的时候提供完成处理模块,但是如果你想知道你的应用程序还能运行多长时间,你可以通过UIApplication对象的backgroundTimeRemaining属性来获得。

在你的完成处理模块中,你可以加入一些必须的代码来关闭你的任务。但是,完成处理模块中的任何代码都不应该耗费太长的时间去执行,因为你的完成处理模块一旦被调用,就说明你的应用程序已经快要被关闭了。因此,只执行最少的清理状态信息并结束任务。

在后台执行下载任务

当下载文件时,应用程序应该使用NSURLSession对象来开始下载,这样系统就能控制下载的进程即使应用程序被挂起或终止。当你配置NSURLSession对象进行后台传输时,系统用一个单独的队列管理这些任务并以常规方式将传输的状态报告给你的应用程序。如果你的应用程序在传输正在进行时被终止,系统会在后台继续传输,并在传输完成或一个甚至多个任务需要你的应用程序时启动你的应用程序(若果使用)。

为了支持后台传输,你必须合适地配置你的NSURLSession对象。为了配置NSURLSession有必须先创建一个NSURLSessionConfiguration对象并给它的一些属性赋予合适的值。然后将这个NSURLSessionConfiguration对象在初始化NSURLSession对象时传递过去。

创建支持后台下载的NSURLSessionConfiguration对象的过程如下:

1.使用NSURLSessionConfigurationbackgroundSessionConfigurationWithIdentifier:方法创建配置对象。

2.将配置对象的sessionSendLaunchEvents属性的值设置为YES

3.如果你的应用程序在前台进行转移,建议你将sessionSendsLaunchEvents属性设置为YES

4.根据需要配置配置对象的任何其他属性。

5.使用配置对象创建您的NSURLSession对象。

一旦配置完成,你的NSURLSession对象会在合适的时间将上传和下载任务移交给系统。如果任务在你的应用程序仍在运行时完成(无论是在前台或是后台),NSURLSession对象都会以常规方式通知它的代理。如果任务还未完成时你的应用程序就被终止,系统会自动地在后台管理任务。如果用户终止了你的应用程序,系统会停止任何待处理的任务。

当所有与后台会话管理的任务完成时,系统会重启被终止的应用程序(假定sessionSendsLaunchEvents属性被设置为YES而且这个应用程序不是被用户强制终止的)并调用应用代理的application:handleEventsForBackgroundURLSession:completionHandler:方法。(系统还可以重新启动应用程序来处理身份验证或其他需要你的应用程序注意的任务的相关事件)在执行该委托方法时,请使用提供的标识符创建一个新的与之前相同的NSURLSessionConfigurationNSURLSession对象。 系统将你的新会话对象重新连接到先前的任务,并将其状态报告给会话对象的委托。

执行长时间运行的任务

对于需要更多后台执行时间的任务,你必须请求特定的权限才能在后台运行它们而不被挂起。iOS中,只有特定类型的应用程序被允许在后台运行:

  • 在后台播放音频内容给用户,比如音乐播放器
  • 在后台录制音频文件
  • 使用户随时了解其位置的应用程序,比如导航应用程序
  • 支持VoIP的应用程序
  • 需要经常性的下载和处理新内容的应用程序
  • 周期性的从外部配件接收更新的应用程序

使用这些服务的应用程序必须声明其支持的服务,并使用系统框架来实现这些服务的相关方面。

声明你的应用程序支持的后台模式

你必须在应用程序使用后台任务之前声明你要支持的后台任务类型。在Xcode 5和之后,你需要在你工程的Capabilities选项卡中声明你要支持哪些后台模式。启用后台模式选项将UIBackgroundModes键添加到应用程序的Info.plist文件中。

下表列出了你可以指定的后台模式的值:

Xcode后台模式 UIBackgroundModes 值 描述
音频和AirPlay audio 应用程序在后台播放或录制音频内容。用户必须在第一次使用前就授权使用麦克风。
位置更新 location 使用户随时知道他们的位置,即使应用在后台运行。
网络电话 voip 应用程序提供给用户通过网络连接进行通话的能力。
Newsstand下载 newsstand-content Newsstand类型的应用程序在后台下载并处理报纸或杂志内容。
外部附件通信 external-accessory 应用程序与需要通过外部附件框架定期提供更新的硬件配件配合使用。
使用蓝牙设备 bluetooth-central 应用程序使用需要通过Core Bluetooth框架定期发送更新的蓝牙设备。
作为蓝牙LE附件 bluetooth-peripheral 应用程序通过Core Bluetooth框架支持外设模式下的蓝牙通信。使用此模式需要用户授权
后台抓取 fetch 应用程序定期的从网路下载并处理少量数据。
远程推送 remote-notification 应用程序想要在接收到一个远程推送时开始下载内容。

以上每种模式都让系统知道应该在合适的时间唤醒或启动应用程序来响应相关的事件。

追踪用户位置

在后台追踪用户的位置的方式有好几种,大多数方式实际上并不需要你的应用程序在后台不断的运行。

  • 重大位置变更
  • 仅在前台定位服务
  • 后台定位服务

对于不需要高精度位置数据的应用程序来说,推荐使用重大位置变更定位服务。这个服务只有在用户的位置发生非常重大的变化时才会产生位置更新;它对社交类应用程序或者给用户提供不是很重要的位置相关信息的应用程序来说是非常理想的定位方式。如果当一个位置更新发生时应用程序被终止,系统会在后台唤醒它来处理这个更新。如果应用程序开始使用了这个服务然后被终止,当新的位置更新产生时,系统会自动重启它。

仅前台定位服务和后台定位服务都使用标准的Core Location服务获取位置数据。唯一的区别是,如果应用程序被挂起,则仅前台定位服务停止发送更新。 前台定位服务适用于只在前台需要位置数据的应用程序。

你可以在Xcode工程中的Capabilities选项卡中启用支持定位服务(你也可以通过在Info.plist文件中设置UIBackgroundModes的值为location来启用这个服务)。启用这个服务并不会阻止系统挂起你的应用程序,但是它会告知系统无论何时新的位置更新被发送过来都应该唤醒应用程序来处理。

重要提示:鼓励你谨慎使用标准的定位服务或改用重要的位置更改服务。 定位服务需要经常使用iOS设备的板载无线电硬件。 连续运行这个硬件会消耗大量的电量。 如果你的应用程序不需要向用户提供精确且连续的位置信息,则最好尽量减少使用位置服务。

在后台播放或录制音频

一个需要连续播放或录制音频的应用程序(即使应用处在后台)可以注册后台服务,实现即使在后台也能执行这些任务。你可以在Xcode工程中的Capabilities选项卡中启用服务(你也可以通过在Info.plist文件中设置UIBackgroundModes的值为audio来启用这个服务)。在后台播放音频内容的应用程序必须播放听得见的内容而不能是无声的。

后台音频应用程序的典型例子包括:

  • 音乐播放程序
  • 音频录制程序
  • 支持通过AirPlay播放音频或视频的程序
  • VoIP程序

UIBackgroundModes键包含audio值时,系统的媒体框架会自动阻止相关的应用程序被挂起。只要应用程序还在播放视屏或音频内容,录制音频,它就还能在后台运行。然而,一旦录制或播放停止,就会被系统挂起。

你可以使用任何系统音频框架来处理后台音频播放,并且使用这些框架的过程和在前台使用相同(对于通过AriPlay播放视频内容来说,你可以使用Media Player或AVFoundation框架来实现)。因为应用程序在播放媒体文件时不会被挂起,所以即使应用程序在后台也能正常的进行回调操作。在你的回调中,你应该只做为播放提供数据的工作,不应该在回调中执行任何与播放无关的任务。

在任何给定的时刻,因为可能有不止一个应用程序支持音频服务,所以由系统来决定哪个应用程序能够播放或录制音频。前台应用程序总是有优先的音频操作权利。可能有不止一个应用程序被允许在后台播放音频,这个时候决定哪个应用程序能够播放音频就取决于每个应用程序的音频会话的配置。

实现一个VoIP应用程序

一个Voice over Internet Protocol应用程序允许用户通过互联网而不是设备的蜂窝网络设备进行语音通话。这样的一个应用程序需要为它的服务维持一个持续的网络连接,以便它能接收到打进来的电话和其它相关数据。系统允许VoIP应用程序被挂起并给它提供了监测它们的sockets的便利,而不是让它一直处于唤醒状态。当检测到传入流量时,系统唤醒VoIP程序并将socket的控制权交还给它。

为了配置VoIP应用程序,你必须:

  • 在Xcode工程中的Capabilities选项卡中启用服务(你也可以通过在Info.plist文件中设置UIBackgroundModes的值为voip来启用这个服务)。
  • 为VoIP应用程序配置一个socket。
  • 在移动到后台之前,调用setKeepAliveTimeout:handler:方法来安装一个定期执行的程序。你的应用程序可以使用这个处理程序来保持服务连接。
  • 配置你的音频会话来操作进入或退出活跃的使用状态的转换。

设置UIBackgroundModes的值为voip让系统知道,当VoIP应用程序需要管理它的网络会话时,系统应该允许它在后台运行。为了让VoIP应用程序总是可用,系统会在启动后立刻重新启动拥有这个键值的应用程序。

大多数的VoIP应用程序也需要配置后台音频模式,因为它也需要在后台发送音频内容。因此,你应该将UIBackgroundModes的值设置为audiovoip。如果你不这样做的话,你的应用程序将不能在后台播放或录制音频内容。

适时的获取少量内容

需要定期的检查新内容的应用程序可以请求系统唤醒它们,以便它们可以初始化一个获取内容的拉取操作。为了支持这种模式,你需要在Xcode工程中的Capabilities选项卡中启用服务(你也可以通过在Info.plist文件中设置UIBackgroundModes的值为fetch来启用这个服务)。启用这个服务并不能保证系统会给你的应用程序任何时间来执行后台拉取操作。系统必须在你的应用程序拉取内容的请求和其它应用程序以及系统自身之间做出平衡。在评估所有信息后,如果有很好的机会的话,系统会给请求拉取内容的应用程序一些执行时间。

当有好机会产生时,系统会唤醒或启动你的应用程序到后台并调用应用程序代理对象的application:performFetchWithCompletionHandler:方法。使用这个方法来检查新内容,如果新内容可用则开始下载操作。一旦新内容下载完成,你必须将新内容是否可用的结果传递给提供好的完成处理块。执行这个块告诉系统它可以将你的应用程序转换到挂起状态并评估其使用功率。可以快速下载少量内容并在它们有可用的下载内容时准确反应的应用程序,比起花费更长的下载时间或声称有可用的下载内容但没有下载任何东西的应用程序,更可能在未来获得执行时间。

在下载任何内容时,推荐你使用NSURLSession类来开始和管理你的下载。

使用推送通知来开始下载

如果你的服务器在有新的应用程序可用内容时向用户的设备发送了一个推送通知,你可以请求系统在后台运行你的应用程序并立即开始下载新的可用内容。这种后台模式意图在于尽可能减少从你的用户看见推送通知到你的应用程序可以展示相关内容之间的时间。应用程序通常会在用户看见推送通知的差不多相同的时间被唤醒,但是仍会给你更多的准备时间。

为了支持这种模式,你需要在Xcode工程中的Capabilities选项卡中启这项用服务(你也可以通过在Info.plist文件中设置UIBackgroundModes的值为remote-notification来启用这个服务)。

对于一个使用推送通知来触发下载操作的应用程序来说,通知的有效内容必须包含值为1content-available的键。当这个键值对被检测到时,系统会启动或唤醒你的应用程序到后台同时调用应用程序的代理对象的application:didReceiveRemoteNotification:fetchCompletionHandler:方法。你应该在这个方法里实现对相关内容的下载并将下载好的内容在加入到你的应用程序中。

在下载任何内容时,推荐你使用NSURLSession类来开始和管理你的下载。

在后台下载新闻站内容

下载新闻和新的杂志文章的新闻站应用程序可以注册在后台进行这些下载。你需要在Xcode工程中的Capabilities选项卡中启这项用服务(你也可以通过在Info.plist文件中设置UIBackgroundModes的值为newsstand-content来启用这个服务)。当你提供这个关键字时,如果你的应用程序没有在运行,系统会启动你的应用程序以便它能开始下载新的文章。

当你使用Newsstand Kit框架来开始一个下载时,由系统为你的应用程序操作下载的进程。即使你的应用程序被挂起或终止,系统仍会继续下载文件。当下载操作完成后,系统将下载好的文件传输到你的应用程序的沙盒并向你的应用程序发送一个通知。如果应用程序没有在运行,这个通知会唤醒它并给它一个处理新的下载文件的机会。如果在下载过程中发生了错误,你的应用程序也会这样被唤醒来处理这个错误。

与外部附件通信

使用外部附件的应用程序可以请求在附件发送了一个更新时被唤醒,即使它处在挂起状态。这种支持对于某些定期发送数据的附件来说是非常重要的,比如心率监视器。你需要在Xcode工程中的Capabilities选项卡中启这项用服务(你也可以通过在Info.plist文件中设置UIBackgroundModes的值为external-accessory来启用这个服务)。当你启用这个模式时,外部附件框架不会关闭活跃的外部附件会话。当外部附件发送来新的内容时,这个框架唤醒你的应用程序以便它能处理这些数据内容。在外部附件建立连接或失去连接时,系统也会唤醒应用程序来进行处理。

任何支持附件更新后台处理的应用程序都必须遵循以下基本准则:

  • 应用程序必须提供一个界面,让用户来开始或者停止附件更新事件的发送。

  • 一旦被唤醒,应用程序大约有10S时间来处理数据。理想情况下,它应该尽可能快速地处理数据然后转换到挂起状态。但是,如果需要更多的时间,应用程序可以使用beginBackgroundTaskWithExpirationHandler:方法来申请额外的执行时间。

与蓝牙附件通信

使用蓝牙外设的应用程序可以请求在外设发送了一个更新时被唤醒,即使它处在挂起状态。这种支持对于需要定期发送数据的Bluetooth-LE外设来说是非常重要的。你需要在Xcode工程中的Capabilities选项卡中启这项用服务(你也可以通过在Info.plist文件中设置UIBackgroundModes的值为bluetooth-central来启用这个服务)。当你启用这个模式时,Core Bluetooth框架会保持相应外设的任何活跃会话连接。此外,当有新的数据从外设传来,系统会唤醒应用程序让他能够处理数据。在外设建立连接或失去连接时,系统也会唤醒应用程序来进行处理。

iOS 6中,一个使用蓝牙外设的应用程序也可以在外设模式下运行。要充当蓝牙外设,你需要在Xcode工程中的Capabilities选项卡中启这项用服务(您也可以通过在应用程序Info.plist文件中包含UIBackgroundModes键和bluetooth-peripheral值来启用此支持)。启用此模式可让Core Bluetooth框架在后台简单地唤醒应用程序,以便它可以处理外设的相关请求。

支持蓝牙数据后台处理的任何应用程序都必须基于会话,并遵循以下基本准则:

  • 应用程序必须提供一个界面,允许用户启动和停止蓝牙事件的传递。

  • 被唤醒后,应用程序大概需要10秒钟才能处理数据。理想情况下,它应该尽可能快地处理数据,并允许自己再次暂停。但是,如果需要更多的时间,应用程序可以使用beginBackgroundTaskWithExpirationHandler:方法来请求更多的时间,它应该只有在绝对必要的时候才这样做。

在后台获得用户的注意

通知是处在挂起,在后台运行或没有运行的应用程序获得用户的注意的一种方式。应用程序可以使用本地通知来显示提醒框,播放声音,标记应用程序的图标或者全部一起使用。比如,一个闹钟应用程序可能会使用本地通知来播放闹铃声并显示一个提醒框来使闹钟不可用。当一个通知被发送给用户,用户必须决定是否授权让应用程序来到前台。如果应用程序已经在前台,本地通知将会被静默的发送给你的应用程序而不是发送给用户。

为了安排本地通知的发送,需要创建一个配置了通知的各个参数的UILocalNotification类的实例并调用UIApplication类的方法。本地通知对象包含了发送通知的类型和在什么时间发送它的信息。UIApplication类的方法提供了是立即发送还是按时间表发送通知的选项。

下面的代码片段展示了如何安排一个由用户设置的使用了日期和时间的闹钟的例子。这个例子在一个时间只配置了一个闹钟并在安排它之前终止了前一个闹钟(你的应用程序在任何给定的时刻都不能拥有超过128个处在活跃状态的本地通知,它们每一个都能设置成以固定的时间间隔重复)。如果闹钟被触发时,应用程序没有运行或者处在后台,闹钟会弹出提醒框并在后台播放音频。如果应用程序是活动且处在前台,则会调用应用程序的代理对象的application:didReceiveLocalNotification:方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- (void)scheduleAlarmForDate:(NSDate*)theDate {
UIApplication* app = [UIApplication sharedApplication];
NSArray* oldNotifications = [app scheduledLocalNotifications];

// Clear out the old notification before scheduling a new one.
if ([oldNotifications count] > 0)
[app cancelAllLocalNotifications];

// Create a new notification.
UILocalNotification* alarm = [[UILocalNotification alloc] init];
if (alarm)
{
alarm.fireDate = theDate;
alarm.timeZone = [NSTimeZone defaultTimeZone];
alarm.repeatInterval = 0;
alarm.soundName = @"alarmsound.caf";
alarm.alertBody = @"Time to wake up!";

[app scheduleLocalNotification:alarm];
}
}

本地通知使用的音频文件和推送通知使用的要求相同。自定义的音频文件必须位于你应用程序主要包中且必须是以下几种格式:Linear PCM,MA4,μ-Law或者a-Law。你也可以指定UILocalNotificationDefaultSoundName常量来使设备播放默认的提醒声音。当通知被发送且音频被播放时,系统也会触发设备震动来配合。

何时启动应用程序进入后台

支持后台执行的应用程序可能会被系统重启来处理发生的事件。如果应用程序不是被用户强制退出,系统会启动应用程序在下列事件发生时:

  • 对于定位应用程序
    • 系统收到一个满足发送给应用程序标准的位置更新。
    • 设备进入或退出一个已注册的区域。
  • 对于音频应用程序,音频框架需要应用程序来处理某些数据。
  • 对于蓝牙应用程序
    • 应用程序作为从连接的外设接收数据的核心角色。
    • 应用程序作为从连接核心接收命令的外设。
  • 对于后台下载应用程序
    • 应用程序收到一个包含 content-available 键并且值为 1的远程通知。
    • 系统在随机时间唤醒应用程序来开始新内容的下载。
    • 使用NSURLSession对象在后台下载内容的应用程序,当这个会话相关的任务全部成功完成或发生了一个错误。
    • Newsstand应用程序内容下载完成。

在大多数情况下,系统并不会重启被用户强制退出的应用程序。定位应用程序是个例外,在iOS8和之后。如果不是的话,用户必须显式的启动应用程序或者重启设备,系统才能自动的启动程序进入后台。当启用密码保护时,在用户第一次解锁设备之前,系统不会启动任何应用程序进入后台。

成为一个负责的后台运行应用程序

在使用系统资源和硬件时,前台应用程序始终比后台应用程序的优先级高。后台应用程序需要为这个差异做准备并调整它们的行为:

  • 不要在你的代码中进行任何OpenGL ES调用。在后台运行时,你绝不能创建EAGLContext对象或发出任何OpenGL ES绘图命令。使用这些会使你的应用程序被立即终止。应用程序必须保证任何先前提交的命令在移入后台之前完成。
  • 在挂起之前停止任何Bonjour-related服务。在你的应用程序移入后台但未被挂起之前,它应该从Bonjour注销并关闭任何与网络服务相关的监听sockets。一个挂起的应用程序无论如何不能响应任何传入的服务请求。如果你没有关闭Bonjour服务,在应用程序挂起时,系统会自动的关闭它们。
  • 准备好处理基于网络的sockets的连接失败。系统可能会销毁socket连接,当你的应用程序因为某些原因被挂起时。只要你的基于网络的socket代码准备好了如何处理其他类型的网络失败,比如使用失败信号或网络转化,socket被销毁就不会导致出现任何不寻常的问题。当你的应用程序重新开始运行时,如果使用socket遭遇故障,只需重新建立一个。
  • 在转入后台之前保存你的应用程序的状态。处于低内存的情况下,后台应用程序可能会被从内存中移除以释放空间。挂起的应用程序首先被移除,并且不会在移除之前通知应用程序。因此,应用程序应该利用iOS 6及之后提供的状态保存机制将应用程序状态信息保存到磁盘。
  • 在转入后台时移除对任何不需要的对象的强引用
  • 在挂起之前停止使用共享系统资源。与共享系统资源进行交互的应用程序应该在被挂起之前停止使用这些资源。前台应用程序总是拥有这些资源的优先使用权。当你的应用程序挂起时,如果被发现它在使用这些共享资源,则会被系统杀死进程。
  • 避免更新窗口和视图。因为你的应用程序的窗口和视图在后台是不可见的,你应该避免更新它们。如果你的应用程序需要在系统拍摄快照前更新窗口的内容的话则是一种例外情况。
  • 响应外部附件的连接和断开通知。对于和外部附件通信的应用程序来说,当应用程序转入后台时系统会自动的发送一个断开通知。应用程序必须注册这个通知并用它来关闭当前附件的会话。当应用程序转入前台时,一个匹配连接的通知被发送,给应用程序重新连接的机会。
  • 在转入后台时清理活动的提醒框的资源。为了在各个应用程序之间进行切换时保存上下文,在你的应用程序进入后台时,系统不会自动地释放上拉菜单或提醒视图。在应用程序转入后台之前,你需要提供合适的清理行为。
  • 在转入后台之前从视图中移除敏感信息。当应用程序转入后台时,系统会对应用程序的主窗口拍摄快照,当应用程序转入到前台时,这个快照会短暂的显示。在从applicationDidEnterBackground:方法返回之前,你应该隐藏或混淆可能被作为快照一部分拍摄的密码和其它敏感的个人信息
  • 在后台运行时尽可能的少做工作。给与后台应用程序的执行时间相比于前台应用程序来说有更多的限制。应用程序不应该在后台执行太长时间,这可能导致应用程序被终止。

选择退出后台执行

如果你不希望你的应用程序在后台运行,你可以通过将值为YESUIApplicationExitsOnSuspend键加入Info.plist来显式的退出后台模式。当一个应用程序选择退出后台,它的生命周期将在未运行,非活动和活动状态之间转换,永远不会进入后台或被挂起状态。当用户按下Home按钮来退出应用程序时,应用程序代理对象的applicationWillTerminate:方法将会被调用,应用程序将有大约5秒时间在它被终止或移入未运行状态之前来执行清理任务并退出。

强烈不鼓励退出后台执行,但在某些情况下可能是首选。 具体来说,如果后台执行的编码对你的应用程序来说增加了很大的复杂性,那么终止应用程序可能会更简单。 此外,如果你的应用程序消耗大量内存,并且无法轻松释放任何内存,系统可能会迅速杀死你的应用程序,为其他应用程序腾出空间。 因此,选择终止,而不是切换到后台,可能会产生相同的结果,并节省你的开发时间和精力。

作者

Y2hlbmdsZWk=

发布于

2015-10-21

更新于

2021-09-01

许可协议