如何避免过早加载控制器 view

前言

最近做了一波性能优化,发现项目中有一部分控制器的 view 在没有展示给用户之前就已经加载到内存中了,这其实是一种浪费,而且不符合懒加载的原则。

那什么情况会导致控制器的 view 过早加载?应该如何避免这种情况呢?今天就来聊聊这个话题。

UIViewController 生命周期

UIViewController 是 iOS 开发的基本组件。为了了解上边提到的提前加载控制器,我们需要了解视图控制器的生命周期。

正常的生命周期调用顺序是:

  1. init() --- 初始化视图控制器

  2. loadView() --- View 被创建并加载到内存中

  3. viewDidLoad() --- 加载 View 后调用

  4. viewWillAppear(_:) --- 在控制器出现之前调用

  5. viewDidAppear(_:) --- 在控制器出现之后调用

  6. viewWillDisappear(_:) --- 在控制器消失之前调用

  7. viewDidDisappear(_:) --- 在控制器消失之后调用

  8. deinit() --- 在控制器销毁之后调用

发现过早加载的问题

这里需要重点说一下 loadView 方法和 viewDidLoad 方法。

当控制器调用 init() 创建之后,其 View 默认的值是 nil,当你第一次调用 view 的时候(即self.view) view 才会创建,这是控制器创建 view 的原理。

view 的创建是通过调用 loadView 方法进行的,loadView 调用完成之后紧接着就会调用 viewDidLoad 方法,而我们大部分的初始逻辑是写在 viewDidLoad 里的。

此时,如果并不需要展示 view,就会导致一些额外的内存占用。

如何避免这种问题

经过我个人项目的经验和问题排查,大概有以下几种情况会导致这种问题,需要在开发中尽量避免。

1、控制器尽量在需要的时候才加载

比如常见的多 tab 切换页面,每个 tab 都是一个控制器,这时候有一种做法是把所有 tab 的控制器都创建出来,等到某个 tab 的时候直接把创建好的拿来用。

从内存最小化的原则上来看,这种方式并不合理,控制器尽量是懒加载的,即在切到某个 tab 的时候再创建。

2、避免在 init 方法中直接调用 view 属性

从控制器 init() 方法内访问 self.view 绝对是一个错误,因为它会过早调用 loadView() 和 viewDidLoad()。一方面,不是所有调用 init 之后就会展示,另一方面这种情况往往会加重主线程的负担,因为 viewDidLoad() 中会有比较多的逻辑。

3、创建控制器之后不要立即调用 view 属性

有些时候的确可能提前创建控制器,比如使用 UITabBarController 控件,就需要提前把 TabBar 上的控制器都创建出来,但是创建完成之后,不要在切过去之前调用控制器的 view 属性,否则还是会提前创建 view,导致性能下降。

利用全局断点发现问题

特别是大项目,这种问题很难被发现,一个一个排查又不太现实,利用全局断点可以帮助我们快速发现这个问题。

首先选中 Xcode 左侧菜单栏的断点 Tab(快捷键 command + 8 ),然后点击左下角加号按钮,并选择 Symbolic Breakpoint...:

为了能够捕获 viewDidLoad 方法的调用,需要在断点弹出框的 Symbol 中填写 -[UIViewController viewDidLoad],之后点击 Add Action 按钮添加一个日志打印,这里我们填写 po $arg1,最后勾选一下底部的勾选框 Automatically continue after evaluating actions,意思是当触发这个断点的时候不要停止代码运行。

最后,我们当我们再次运行代码,每个控制器在执行 viewDidLoad 方法时就会在控制器把这个控制器名称打出来,方便我们查看哪些 viewDidLoad 被提前调用了。

在之前的文章中还讲过一篇关于控制器销毁的文章,感兴趣可以去看看:

如何检测控制器循环引用

点击下方公众号卡片,关注我,每天分享一个关于 iOS 的新知识

本文同步自微信公众号 "iOS新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!

相关推荐
茶底世界之下7 小时前
雨夜街角裁成方图,人物与冷暖光还能共存吗?
ios
youdexiang10 小时前
IOS录音APP拍照记录能和音频同步吗
ios·音视频
2501_9159090611 小时前
Windows 打开 Xcode 工程,编译调试 Xcode 项目并和 Mac 同事协作
ide·windows·vscode·macos·ios·个人开发·xcode
互联网江湖11 小时前
iPhone Duo跌倒,国产折叠屏手机吃饱?
ios·智能手机·iphone
zwd20051 天前
词频是什么?生词滑块 zipf 3.0 到 5.0 怎么调:同一屏从 0 个生词到 11 个
ios·iphone·效率工具·英语学习·词频·屏幕翻译
茶底世界之下1 天前
灯暖窗冷,色温要不要继续降?用 Awaking 看混合光的取舍
ios
2501_916007471 天前
Windows OpenSSL 生成 iOS 证书,制作 p12 与描述文件,KXBuild 签名实操
windows·vscode·ios·objective-c·个人开发·swift·敏捷流程
最强小杰1 天前
gpt-image-2.5-sunburst + OpenAI SDK + Cline 怎么接?完整图生图与局部重绘教程
gpt·ios·ai·iphone
kk_net88991 天前
FSNotes:macOS 和 iOS 上的开源笔记管理器
笔记·其他·macos·ios
00后程序员张1 天前
Windows 开发 iOS App 入门,用 SwiftUI 写第一个 iOS App 装到 iPhone
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程