当前位置: 首页 > news >正文

iOS 层级的生命周期按三部分(App / UIViewController / UIView)

App(应用)生命周期 — 状态与关键回调

状态(概念)

  • Not running:未启动或已被系统终止。

  • Inactive:前台但不接收事件(短暂过渡,如来电、控制中心出现)。

  • Active:前台并接收事件(正常运行)。

  • Background:在后台仍可执行有限任务(有短暂后台时间或注册了后台任务)。

  • Suspended:被系统挂起,不再执行代码但仍驻留内存(可被系统随时回收)。

关键回调(iOS 13 之前 / 多场景之前) — UIApplicationDelegate

func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Boolfunc applicationDidBecomeActive(_ application: UIApplication)
func applicationWillResignActive(_ application: UIApplication)
func applicationDidEnterBackground(_ application: UIApplication)
func applicationWillEnterForeground(_ application: UIApplication)
func applicationWillTerminate(_ application: UIApplication)

iOS 13+(多窗口/场景):生命周期以 Scene 为单位,使用 UISceneDelegate

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options: UIScene.ConnectionOptions)
func sceneDidBecomeActive(_ scene: UIScene)
func sceneWillResignActive(_ scene: UIScene)
func sceneWillEnterForeground(_ scene: UIScene)
func sceneDidEnterBackground(_ scene: UIScene)
func sceneDidDisconnect(_ scene: UIScene)

注:iPad / 多任务下每个 scene(窗口)独立,必须使用 SceneDelegate 来处理与窗口相关的生命周期。

实用要点

  • didFinishLaunchingWithOptions:做一次性初始化(依赖注入、第三方 SDK、数据库迁移等)。避免在这里做耗时同步工作。

  • scene(_:willConnectTo:):创建/配置窗口、根 VC(iOS 13+)。

  • applicationWillResignActive / sceneWillResignActive:短暂停止交互(保存少量状态、暂停游戏)。

  • applicationDidEnterBackground / sceneDidEnterBackground:进行持久化、释放能在后台释放的资源;若需额外时间用 beginBackgroundTask(expirationHandler:) 或使用 BGTaskScheduler 注册后台任务。

  • applicationWillTerminate 不总会被调用(用户强杀或系统崩溃可能不会触发),关键数据应在进入后台时保存。

UIViewController(控制器)生命周期 — 顺序与用途

典型调用顺序(展示时)

  1. init(nibName:bundle:) / init?(coder:)(Storyboard/Nib)

  2. loadView()(若未使用 storyboard,会在此创建 view

  3. viewDidLoad() —— 视图加载完成(只调用一次)

  4. viewWillAppear(_:) —— 即将显示(每次出现都会调用)

  5. viewWillLayoutSubviews() —— 布局子视图前

  6. viewDidLayoutSubviews() —— 布局子视图后

  7. viewDidAppear(_:) —— 已显示(适合启动动画、启动定时器)

离开/消失

  • viewWillDisappear(_:) —— 即将消失(保存临时状态、停止输入)

  • viewDidDisappear(_:) —— 已消失(停止定时器、移除观察者、释放重资源)

  • deinit —— VC 被释放(非生命周期方法,但重要,确认被释放避免内存泄漏)

其他重要回调

  • loadView():如果你手写界面并不使用 Storyboard/Nib,可重写并 self.view = someView不要在 loadView() 执行复杂业务逻辑。

  • viewIfLoaded / isViewLoaded:检查 view 是否已加载。避免强制访问 view 导致提前加载。

  • prepare(for:sender:):segue 前执行数据传递。

  • traitCollectionDidChange(_:):尺寸类 / 深色模式改变时回调。

  • willMove(toParent:) / didMove(toParent:):用于子控制器管理(addChild / removeFromParent 时调用)。

子控制器管理
当把一个 VC 作为子 VC 嵌入时,正确调用顺序:

parent.addChild(child)
parent.view.addSubview(child.view)
child.didMove(toParent: parent)

移除时要先 willMove(toParent: nil) -> removeFromParent() -> removeFromSuperview()(或相似顺序)。

什么时候做什么(实用建议)

  • 初始化模型/一次性布局:viewDidLoad()。(创建 UI 元素、注册 table view cell、绑定数据)

  • 每次进入页面需要刷新:viewWillAppear(_:)(刷新数据、更新导航栏状态)。

  • 启动动画/开始计时器/开始播放:viewDidAppear(_:)(确保界面已在屏幕上)

  • 停止动画/暂停计时器/保存临时状态:viewWillDisappear(_:) 或 viewDidDisappear(_:)

  • 更新 Auto Layout 相关约束:updateViewConstraints()(或在 viewDidLoad 添加约束,避免在 layoutSubviews 中频繁添加约束)。

  • 处理内存/监听:添加通知观察器在 viewDidLoad 或 viewWillAppear,移除在 viewWillDisappear 或 deinit(取决于观察者的生命周期)。

常见坑

  • 把耗时操作放到 viewDidLoad 且阻塞主线程 → UI 卡顿。应放到后台线程,完成后回到主线程更新 UI。

  • viewDidLayoutSubviews 会多次调用(布局过程中),不要在里边重复添加约束或做昂贵操作。

  • Modal 默认样式从 iOS 13 起变成 card / pageSheet,可能不会触发 presenting VC 的 viewWillDisappear/viewDidDisappear(因为 presenting VC 仍可见一部分),注意这一点在处理暂停/恢复逻辑时会有影响。

UIView(View)生命周期 — 关键方法与布局绘制

创建与加载

  • init(frame:):代码创建视图时调用。

  • init?(coder:):从 storyboard / nib 加载时调用。

  • awakeFromNib():从 nib 加载并连接 outlet 后调用(可以在这里做额外初始化)。

添加/移除与显示

  • willMove(toSuperview:) / didMoveToSuperview():在被加入/移除父视图前后调用。

  • willMove(toWindow:) / didMoveToWindow():当视图加入某个 window(或从 window 移除)时调用 —— 启动/停止与屏幕显示相关的任务(如 CADisplayLink、动画、OpenGL/Metal 渲染线程)。

布局与约束

  • setNeedsLayout():标记需要布局 -> 系统会在下一个循环调用 layoutSubviews()

  • layoutIfNeeded():立即触发布局(如果有 pending layout)。

  • layoutSubviews():手动布局子视图(在没有使用 Auto Layout 或部分自定义布局时重写)。会在 bounds 变化或 setNeedsLayout() 后被多次调用。

  • updateConstraints():当需要改变约束时重写并在最后调用 super.updateConstraints()。优点:约束更新是在约束更新阶段进行,避免在 layoutSubviews 中添加约束。

绘制

  • draw(_ rect: CGRect):用于自定义 Core Graphics 绘制(只在视图需要重绘时调用)。调用 setNeedsDisplay() 来触发。避免在这里做非绘制逻辑或耗时计算(会阻塞主线程)。

其他

  • intrinsicContentSize:对于基于内容尺寸的组件(如自定义 label/按钮),重写以支持自动布局。

  • contentMode 与 setNeedsDisplay():控制是否在 bounds 改变时需要重绘。

  • UIResponder 的触摸事件(touchesBegan 等)属于 view 的生命周期响应范畴。

快速参考表(什么时候做什么)

  • 一次性初始化(内存中只需做一次):init / awakeFromNib / viewDidLoad

  • 每次页面出现前刷新 UIviewWillAppear(_:)

  • 页面完全显示后启动动画或开始耗时 UI 操作viewDidAppear(_:)

  • 停止动画 / 保存临时状态viewWillDisappear(_:) / viewDidDisappear(_:)

  • 添加观察者:通常在 viewDidLoad 或 viewWillAppear,对应在 deinit 或 viewWillDisappear 移除(与观察者生命周期对齐)

  • 布局相关变更:在 updateConstraints() 或 layoutSubviews()(但避免重复添加约束)

  • 释放重资源(大图片、缓存):进入后台或 viewDidDisappear 中清理

常见问题 & 排查建议

  • VC 不 deinit:很常见,检查循环引用(闭包、Timer、NotificationCenter、delegate 未置 nil)。

  • UI 在旋转/尺寸改变上错位:优先用 Auto Layout,必要时在 viewWillLayoutSubviews 调整常量并调用 layoutIfNeeded()

  • 大量 viewDidLayoutSubviews 调用导致卡顿:检查是否在其中修改约束或触发 setNeedsLayout() 的循环操作。

  • App 后台行为不一致:不要依赖 applicationWillTerminate;使用 sceneDidEnterBackground / applicationDidEnterBackground 做持久化与资源释放;如果需要后台长任务,使用 BGTaskScheduler 或 beginBackgroundTask

http://www.dtcms.com/a/392130.html

相关文章:

  • 第一章 自然语言处理领域应用
  • GitHub又打不开了?
  • OpenAI回归机器人:想把大模型推向物理世界
  • QML学习笔记(五)QML新手入门其三:通过Row和Colunm进行简单布局
  • 按键检测函数
  • CTFshow系列——PHP特性Web109-112
  • 字符函数与字符串函数
  • 酷9 1.7.3 | 支持自定义添加频道列表,适配VLC播放器内核,首次打开无内置内容,用户可完全自主配置
  • Slurm sbatch 全面指南:所有选项详解
  • 使用SCP命令在CentOS 7上向目标服务器传输文件
  • Kindle Oasis 刷安卓系统CrackDroid
  • 最新超强系统垃圾清理优化工具--Wise Care 365 PRO
  • JeecgBoot权限控制系统解析:以具体模块为例
  • 2025年职场人AI认证与学习路径深度解析
  • 硬件开发_基于STM32单片机的智能垃圾桶系统2
  • CSS Display Grid布局 grid-template-columns grid-template-rows
  • 在 Spring Boot 中,针对表单提交和请求体提交(如 JSON) 两种数据格式,服务器端有不同的接收和处理方式,
  • NL2SQL简单使用
  • 数据结构:二叉树OJ
  • 【Linux手册】生产消费者模型的多模式实践:阻塞队列、信号量与环形队列的并发设计
  • Python + Flask + API Gateway + Lambda + EKS 实战
  • 【OpenGL】openGL常见矩阵
  • DeepSeek大模型混合专家模型,DeepSeekMoE 重构 MoE 训练逻辑
  • 450. 删除二叉搜索树中的节点
  • 实用工具:基于Python的图片定位导出小程序
  • 滚珠螺杆在工业机器人关节与线性模组的智能控制
  • 【AI】coze的简单入门构建智能体
  • Python数据分析:函数定义时的装饰器,好甜的语法糖。
  • Java数据结构——包装类和泛型
  • 【C++进阶】C++11的新特性 | 列表初始化 | 可变模板参数 | 新的类功能