# 应用声明周期

当应用在前台或者后台的时候相应系统通知，或者处理其他重要的系统相关事件。

## 概述

应用当前的状态决定什么能做什么不能做。例如，应用前台状态有用户焦点，所以它的优先级高于系统资源，包括cpu。相对的，应用后台尽量做最少的工作，最好不做，因为没有显示。当应用的状态改变的时候，根据情况调整应用行用。

当应用状态改变的时候，UIKit通过相应的代理方法通知应用：

* iOS13和以后，使用 UISceneDelegate 对象响应生命周期事件在基于scene的应用中。
* iOS12及以前，使用 UIApplicationDelegate 对象响应生命周期事件。

> 如果应用支持scene，iOS13及以后一直scene代理。在iOS12及以前，系统使用应用代理。

## 基于scene的生命周期事件

如果支持多scene，UIKit分别发送其相应的生命周期事件。一个scene代表一个设备上运行的UI实例。用户可以针对应用创建多个scene，并且独立的显示和隐藏他们。因为每个scene有独立的生命周期，每个可以处于不同的运行状态。例如，一个scene在前台，同时另外一个在后台或者挂起状态。

下图显示scene的状态转换。当用户或者系统请求创建一个新的scene的时候，UIKit创建并设置其为未连接状态。用户请求的scene快速的切换到前台并显示在屏幕上。系统请求的scene一般移动到后台，可以处理事件。例如，系统可能后台加载一个scene来处理定位事件。当用户隐藏应用界面，UIKit移动相关的scene到后台状态并最终进入挂起状态。UIKit可能在任何时间断开后台或者挂起的scene并回收资源，把scene的状态设置为未连接状态。

![](https://3323963180-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MSfsKp5x5jHFPTcZRiN%2Fsync%2F2b70b5bd7ac9ae74166636d121b6287e182cd5a4.png?generation=1612423197489518\&alt=media)

scene切换来执行以下任务：

* 当UIKit连接一个scene到应用，配置scene的初始化UI并且加载scene需要的数据；
* 当切换到前台激活状态，配置UI并且准备用户交互；
* 离开前台激活状态，保存数据并停止应用行为；
* 进入后台状态时，终止重要任务，释放内存，准备应用截图；
* 断开scene连接，清理scene相关的共享资源；
* 除了scene相关事件，也要使用 UIApplicationDelegate 对象处理app启动事件。

## 基于App的生命周期事件

在iOS12及之前，应用无法支持scene。UIKit发送生命周期事件到 UIApplicationDelegate 对象。App Delegate管理所有的应用界面，包括显示在不同屏幕上的。导致应用的状态影响所有的UI，包括在额外的显示设备上的。

下图显示app delegate对象涉及的状态转换。启动之后，系统设置应用为未激活或者后台状态，基于哪个UI显示在屏幕上。当进入前台状态，系统自动设置引用状态为前台。最后，在应用终止前，在激活和后台状态来回切换。

![](https://3323963180-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MSfsKp5x5jHFPTcZRiN%2Fsync%2Ff2340a0c1933d109fb42b3f7ba16e50c5cbd73b9.png?generation=1612423196323735\&alt=media)

app状态切换执行如下任务：

* 启动时，初始化应用数据结构及UI；
* 激活时，完成UI配置并准备好页面交互；
* 离开激活状态时，保存数据并停止应用行为；
* 进入后台时，停止关键任务，释放尽可能多的内存，准备应用截图；
* 终止时，立即停止所有工作，并释放资源。

## 其他重要事件

除了处理声明周期事件，应用必须处理下表的事件。使用 UIApplicationDelegate 对象处理以下大部分事件。某些情况下，可能需要通知来处理这部分事件。

| 事件          | xx                         |
| ----------- | -------------------------- |
| 内存报警        | 当内存使用高的时候收到。减少内存使用         |
| 受保护数据可用/不可用 | 锁定/解锁设备                    |
| handoff任务   | 当 NSUserActivity 对象需要处理的时候 |
| 时间改变        | 当手机运营商发送时间更新消息等            |
| 打开连接        | 当应用需要打开资源的时候               |

## 内存报警

如果系统可用内存少并且无法通过停止挂起应用来回收内存，UIKit发送内存报警给运行中的任务。UIKit通过以下方式来发送：

* app delegate中的 applicationDidReceiveMemoryWarning 方法；
* 调用激活状态下的 UIViewController 类的 didReceiveMemoryWarning 方法；
* 给注册了的观察者发送 didReceiveMemoryWarngingNotification 对象；
* 发送报警给类型为 DISPATCH\_SOURCE\_TYPE\_MEMORYPRESSURE 的队列；

当应用收到内存报警的时候，尽快尽可能多的释放内存。去掉图片、媒体文件、已经存储在硬盘上的大文件等的引用，可以稍后再加载。移除不用的临时对象的引用。如果活动任务可能会消耗了大量的内存，暂停调度队列或者限制应用执行的并发数。

测试对于内存报警的问题，使用iOS模拟器的模拟内存报警命令。
