当应用进入前台的时候该做什么
回到前台的过程是应用重启一些任务的机会,这些任务是在应用进入后台的时候被停止的。图4-4展示了应用进入前台时所经历的步骤。applicationWillEnterForeground:方法应该撤销在 applicationDidEnterBackground:方法中的操作,并在applicationDidBecomeActive:方法中继续执行与应用启动时一样的任务。
图4-4 从后台转换到前台
注意:UIApplicationWillEnterForegroundNotification通知也可用于跟踪应用是否重新进入前台。应用的对象可以使用默认通知中心来注册这个通知。
准备处理通知队列
当一个应用从挂起状态返回到前台或者后台状态的时候,它都必须为处理通知队列做好准备。一个挂起状态的应用,不能执行任何代码,所以也不能处理相关的通知,包括方向改变、时间改变、偏好改变、以及很多影响应用外观和状态改变的通知。为了确保这些改变没有丢失,系统会把很多相关的通知组成队列,一旦应用再次执行代码的时候(无论是前台还时后台),把它们发送给应用。为了防止应用在恢复的时候因为通知太多而导致负荷超载,系统会将事件合并成一个通知并发送给应用。这个通知反映了从应用被挂以来的净更改。
表4-1 罗列了可以合并且发送到应用的通知。这些通知的大多数都可以直接发送给已注册的观察者。但有一些,例如与设备方向更改相关的,通常会被系统框架截取,并以另一种方式发送给应用。
表4-1 被发送到苏醒应用的通知
事件 | 通知 |
---|---|
连接或断开配件 | EAAccessoryDidConnectNotification EAAccessoryDidDisconnectNotification |
设备方向改变 | UIDeviceOrientationDidChangeNotification 除了此通知外,视图控制器可以自动的更新它们的界面方向。 |
显著的时间变化 | UIApplicationSignificantTimeChangeNotification |
电池电量或者电池状态改变 | UIDeviceBatteryLevelDidChangeNotification UIDeviceBatteryStateDidChangeNotification |
接近状态已改变 | UIDeviceProximityStateDidChangeNotification |
受保护文件状态已改变 | UIApplicationProtectedDataWillBecomeUnavailable UIApplicationProtectedDataDidBecomeAvailable |
连接或断开外接显示器 | UIScreenDidConnectNotification UIScreenDidDisconnectNotification |
显示屏的画面模式已改变 | UIScreenModeDidChangeNotification |
通过Settings应用修改了首选项 | NSUserDefaultsDidChangeNotification |
当前语言或地区设置已改变 | NSCurrentLocaleDidChangeNotification |
用户iCloud账户状态已改变 | NSUbiquityIdentityDidChangeNotification |
通知队列会发送到应用的主运行循环,通常会先于触摸事件和用户输入发送。大多数应用都能快速处理这些事件,不会造成明显的延迟。但是,如果应用出现从后台返回时过于缓慢的情况,请使用Instruments来确定是否是由处理通知的代码导致的。
返回到前台的应用,也可接收更新视图的通知。运行在后台的应用仍可以调用setNeedsDisplay 或 setNeedsDisplayInRect:方法来请求更新视图。但是,因为这些视图不可见,系统会合并这些请求,等到应用会到前台之后再对它们进行更新。
处理iCloud的改变
无论何种原因使得iCloud状态改变,系统都会向应用发送一个NSUbiquityIdentityDidChangeNotification通知。当用户登录或退出iCloud账户,或允许或禁止同步文档和数据时,iCloud状态都会发生改变。这个通知是应用暗示要更新缓存以及任何和iCloud相关的用户界面元素,以适应状态的改变。例如,当用户注销iCloud的时候,你应该删除所有基于iCloud的文件或数据的引用。
如果应用已经提醒过用户是否存储文件到iCloud,那么在iCloud状态改变的时候就不再重复提醒。在第一次提醒用户之后,在应用的本地偏好中存储用户的选择。然后你可以使用Settings束或者应用中的选项来显示该偏好。但是不要再次提醒,除非该偏好当前不在用户默认的数据库中。
处理区域(locale)改变
如果用户在挂起期间改变了所在区域,那么当应用回到前台的时候,你能使用NSCurrentLocaleDidChangeNotification通知来对任何包含区域敏感信息的视图进行更新,例如日期、时间、数字。当然,避免区域相关问题的最好办法是编写代码来让更新视图更容易。例如:
- 当要取回NSLocale对象的时候,使用autoupdatingCurrentLocale类方法。该方法返回一个区域对象,它会根据区域改变而自动更新自身,因此你无需重新创建它。然而,当区域改变时,你仍然需要刷新含有区域派生信息的界面。
- 一旦当前的区域信息发生改变,就应该重新创建任何缓存的数据及数字格式化对象。
更多关于国际化你的代码以便处理区域改变的信息,参见Internationalization and Localization Guide。
处理应用设置的更改
如果应用由通过Settings应用管理的设置时,应用应该观察NSUserDefaultsDidChangeNotification通知。因为用户可以在应用挂起或者后台期间改变设置,你能使用这个通知来回应这些设置中的重要更改。在某些情况下,响应这个通知能帮助关闭潜在的安全漏洞。例如,email程序应该响应用户账户信息的改变。未对这些更改进行检测,会导致隐私和安全方面的问题。具体来说,当前用户可以使用旧的账户信息发送邮件,即使该账户不再属于该用户。
在收到NSUserDefaultsDidChangeNotification通知后,应用应该重新加载相关的设置,如有必要,重新设置它的用户界面。如果密码或其他安全相关的信息改变了,你还应该隐藏之前显示的信息,并强制用户输入新密码。
当应用进入后台时该做什么
当应用从前台进入后台执行时,使用applicationDidEnterBackground:方法来执行以下操作:
- 准备获取应用的图片。当applicationDidEnterBackground:方法返回时,系统的到一张应用用户界面的图片,并将这张图片用于转场动画。如果视图中包含任何敏感信息,你应该在applicationDidEnterBackground: 返回之前隐藏或修改这些界面。如果作为这个处理的一部分,你添加一个新视图到视图层次结构中,你必须强制这些视图自我绘制,如Prepare for the App Snapshot中所述那样。
- 保存所有相关的应用状态信息。在进入后台之前,应用应该已经保存了所有关键用户数据。使用这个到后台的过渡期,保存应用的最后状态。
- 根据需要释放内存。释放任何你不需要的缓存数据,并尽量清理以减少应用的内存占用。占用大量内存的应用会被系统首先终止,所以要释放图像资源、数据缓存、以及其他你不再需要的对象。更多信息,参见Reduce Your Memory Footprint。
应用委托方法applicationDidEnterBackground:大概有5秒钟来完成这些任务并返回。实际上,这些方法应该尽可能块的返回,如果方法超过时间也没有返回,应用会被杀死并清除出内存。如果你仍需要更多时间来执行任务,调用beginBackgroundTaskWithExpirationHandler:方法来请求后台执行时间,然后在辅助线程开始长时运行任务。无论你是否开启后台任务, applicationDidEnterBackground:方法仍将在5秒钟内退出。
注意:除了调用 applicationDidEnterBackground: 方法,系统还发送UIApplicationDidEnterBackgroundNotification通知。你可以使用这个通知来把清理任务分发到应用中的其他对象。
基于应用的功能,在进入后台的时候,应用还要做一些事情。例如,任何活跃的Bonjour服务应该被挂起,停止调用OpenGL ES函数。当进入后台时应该执行的操作的列表,参见Being a Responsible Background App。
后台转换周期
当用户点击Home键、按下休眠/唤醒按钮、或者系统启动其他应用,前台的应用会转换到非活跃状态,然后进入后台状态。这些转换导致调用应用委托的applicationWillResignActive:和applicationDidEnterBackground:方法,如图4-5所示。在从applicationDidEnterBackground:方法返回之后,大多数应用很快进入到挂起状态。请求特定后台任务(如播放音乐)或从系统请求额外运行时间的应用可以继续运行一段时间。
图4-5 从前台进入后台
准备应用快照
在应用委托方法applicationDidEnterBackground:返回不久,系统会得到一张应用视窗的快照。同样,当应用被唤醒来执行后台任务的时候,系统可以可以得到一张新的快照,新快照反映了相关的改变。例如,当应用被唤醒来处理下载项目时,系统会得到新快照,以便能够反映因为合并项目而导致的任何变化。系统在多任务UI中使用这些快照来展示应用的状态。
如果在进入后台之前你改变了视图,你可以调用主视图的snapshotViewAfterScreenUpdates:方法来强制执行这些更改。在视图上调用setNeedsDisplay方法对快照无效,因为在下一个绘图周期之前快照已产生,因此可以防止任何改变被渲染。调用使用值为YES的snapshotViewAfterScreenUpdates:方法,立即更新快照使用的底层缓冲区。
减少内存占用
每个应用都应该在进入后台之前尽可能多的释放内存。系统会在内存中保留尽可能多的内存,但是当内存不足时,它会挂起应用以便回收内存。那些在后台消耗大量内存的应用会被先终止。
实际上,应用一旦不需要某个对象时,就应该移除对该对象的强引用。移除强引用可以让编译器获得释放这些对象的能力,以便可以回收相应的内存。但是,如果你想缓存一些对象以提高性能,你可以在进入后台之前保留它们。
一些应该尽可能移除强引用的对象:
- 你创建的图片对象。(一些返回图片的UIImage 方法,它底层的图片数据会被系统自动清除。更多信息,参见UIImage Class Reference的浏览讨论。)
- 可以从磁盘再次加载的媒体或数据文件。
- 任何不再需要且创建方便的对象。
为了帮助减少应用对内存的占用,系统会在应用进入后台前自动清除一些它代表应用分配的数据。
- 系统清除所有Core Animation层的备份。此功能不会从内存移除应用的图层对象,不会改变现有图层属性。它只是防止这些显示在屏幕上的内容,在后台时仍试图作用于应用。
- 移除任何对缓存图片的系统引用。
- 移除对其他系统管理的数据缓存的强引用,
(本节结束)