ARTICLE · 1268016
iOS 应用生命周期:五个状态与六个回调
iOS 应用生命周期:五个状态与六个回调当你点击手机上微信图标,看到地球和小人的启动页,再看到好友列表。中间过程到底经历了什么? 今天站在专业视角,讲清楚iOS 这一套固定规则编排的状态机。理解这套状态机,是写出不卡顿、不丢数据、不被系统杀掉的应用的前提。 本文把五个状态、AppDelegate 的六个关键时刻、iOS 13 之后的 SceneDelegate 分治,以及三个最常被忽略的坑一次性讲清。 一个 iOS 应用在任何时刻都处于下列五种状态之一,系统负责在它们之间切换,开发者只能在切换的「缝隙」里插手。
最容易混淆的是Inactive和Suspended:Inactive 仍在前台、代码还在跑,只是暂时不收事件(如来电打断游戏);Suspended 已经被系统冻结,代码彻底停摆,只是内存里还留着它的「尸体」,方便你下次回来秒开。 从启动到退场的典型路径: UIKit 用 AppDelegate 的六个方法告诉你「状态要变了」。下面是一份可直接抄进项目的骨架,关键注释写明了每个钩子里该做什么、不该做什么。 一个常被问的问题:用户上划杀掉 app,会走 willTerminate 吗?不会。用户强制退出时系统直接发 SIGKILL,任何回调都不走。willTerminate 只在系统因内存压力回收一个 Suspended 应用、或极少数正常退出路径下才触发。 iPadOS 多窗口和「台前调度」出现后,Apple 把「应用」和「场景」拆开了:一个进程可以有多个 Scene,每个 Scene 有自己独立的生命周期。于是原来 AppDelegate 里那套 active/background 回调,被搬到了SceneDelegate。 这一改带来一个实际坑:如果你的项目同时实现了 AppDelegate 和 SceneDelegate,前/后台的状态切换回调会落在 SceneDelegate 上,AppDelegate 的同名方法不再为场景切换触发。AppDelegate 只保留进程级的两件事: 进程启动:application(_:didFinishLaunchingWithOptions:) 进程终止:applicationWillTerminate(_:) 而场景级的六个方法镜像对应: 判断该写哪一层很简单:跟「单个窗口的 UI 状态」有关就进 SceneDelegate;跟「整个进程只需做一次」有关(如全局配置、第三方 SDK 初始化)才放 AppDelegate。 1. 把 willTerminate 当数据保险箱 它不保证调用,用户强杀和内存回收都绕开它。正确做法是「增量保存」:每次关键操作落盘,或在 didEnterBackground 里就存好,willTerminate 只做收尾。 2. 忘记在 willResignActive 里暂停 来电、控制中心下拉、双击 Home 都会让应用 Inactive。不在这里停掉视频/GPS/计时器,后台会空耗电量和定位权限,用户直接在设置里把权限关了。 3. 误以为 Suspended 是安全的「暂停」 Suspended 只是系统「暂时没杀你」。一旦内存紧张,Suspended 应用是第一批被回收的对象,而且不通知、不回调。所以进后台那一刻就得把可恢复状态存好,别等「下次回来还在」。 Background Modes决定应用被允许在后台干多久。音频播放、位置更新、VoIP、后台刷新等都需要在Info.plist的UIBackgroundModes里声明,否则系统会直接挂起你。注意:后台时间窗口有限(通常 30 秒起,按任务类型延长),超时仍会被冻。 State Restoration是让应用「杀掉后重开像没关过」的机制:系统会在合适时机编码你的视图控制器栈,下次启动自动还原。配合在 didEnterBackground 里存好业务数据,用户几乎感知不到中断。 URL Schemes / Universal Links则反过来——别的应用或网页带着数据把你拉起来。这种「冷启动」路径下,launchOptions里会带着来源信息,需要在 didFinishLaunching 里就分流处理,而不是等界面出来再补。 生命周期不是一组回调方法的堆砌,它是应用与系统、与用户交互的基本契约。把状态转换想清楚,首屏更快、切后台不丢数据、被杀能恢复——这三件事做好了,应用的「体质」就稳了。
一、五个状态:把应用看成状态机
Not Running↓(用户点图标 / 系统拉起) didFinishLaunching → Active↓(来电 / 切后台) WillResignActive → Background↓(无任务可跑) Suspended (内存紧张时直接被系统杀掉 → Not Running)↑(用户切回) WillEnterForeground → Active
二、AppDelegate 的六个关键时刻
import UIKitclass AppDelegate: UIResponder, UIApplicationDelegate {var window: UIWindow?// 1. 启动入口:只做轻量一次性初始化// 重活(网络、大文件解析)别放这,会拖慢首屏,超时被看门狗杀掉func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {window = UIWindow(frame: UIScreen.main.bounds)window?.rootViewController = ViewController()window?.makeKeyAndVisible()return true}// 2. 进入前台并准备收事件:恢复被暂停的任务func applicationDidBecomeActive(_ application: UIApplication) {// 重启音乐、重建网络长连接、刷新 UI}// 3. 即将失去活跃:暂停不该在后台跑的东西func applicationWillResignActive(_ application: UIApplication) {// 暂停游戏循环、停止视频播放、冻结计时器}// 4. 已进后台:保存数据、申请后台任务// 若支持后台执行,用户「退出」走的是这里,不是 willTerminatefunc applicationDidEnterBackground(_ application: UIApplication) {UserDefaults.standard.set("saved", forKey: "appState")// 需要长时间任务时调用 beginBackgroundTask(withName:expirationHandler:)}// 5. 从后台回到前台:撤销后台里做的改动func applicationWillEnterForeground(_ application: UIApplication) {// 刷新受后台影响的 UI、重新拉取数据}// 6. 即将终止:仅有的保存窗口,但「不保证被调用」func applicationWillTerminate(_ application: UIApplication) {// 只做最小化清理,别依赖它保数据}}
三、iOS 13 之后:SceneDelegate 接管多窗口
scene(_:willConnectTo:options:) // 场景创建,等价于启动入口sceneDidBecomeActive(_:)sceneWillResignActive(_:)sceneDidEnterBackground(_:)sceneWillEnterForeground(_:)sceneDidDisconnect(_:) // 场景被销毁(不是 app 退出)















































































