iOS 应用启动性能优化
iOS 应用启动性能优化
iOS 应用启动涉及系统加载可执行文件、运行静态初始化、创建应用对象、搭建首个界面并完成首帧绘制。业务迭代中,统计组件、数据库准备、账户恢复和首页请求会不断加入关键路径。如果缺少测量和分级,启动时间往往在不知不觉中增长。
一、区分启动阶段
可以把启动过程分成两个部分:
- 进入
main之前:系统装载、动态链接、运行初始化代码。 - 进入
main之后:应用代理回调、场景创建、根控制器搭建和首帧渲染。
前一部分主要受二进制结构、动态库数量和静态初始化影响;后一部分则更多由业务代码、布局和数据准备决定。分清阶段,才能避免在错误位置优化。
二、定义用户可感知的完成点
启动回调结束不等于用户可以使用页面。建议同时关注:
- 系统启动画面结束。
- 首个业务画面绘制。
- 首屏主要内容稳定。
- 关键按钮可以响应。
如果首帧很快,但首页随后长时间空白,用户仍会觉得应用很慢。指标应覆盖首帧和业务可用时间。
三、减少静态初始化工作
全局变量和类型静态属性可能在较早阶段初始化。初始化中如果包含文件读取、数据库访问或复杂对象图构建,会推迟应用进入业务代码。
final class FeatureRegistry {
static let shared = FeatureRegistry()
private init() {}
lazy var reportService: ReportService = {
ReportService(configuration: makeReportConfiguration())
}()
}
延迟属性能够把创建时机移动到首次使用,但首次访问仍可能阻塞当前线程。重型准备工作应在明确的异步阶段完成,而不是只包一层 lazy。
四、精简启动回调
应用和场景启动回调只做首屏真正依赖的工作。第三方与内部组件可以分类:
- 启动前必须完成的基础能力。
- 首帧后立即准备的常用能力。
- 进入具体功能时再初始化的低频能力。
- 当前进程完全不需要的能力。
初始化任务之间如果存在依赖,应明确顺序。没有依赖的任务也不应无上限并发,以免争抢处理器和磁盘资源。
五、避免主线程同步读写
账户快照、配置文件和数据库迁移都可能阻塞主线程。首先减少读取量,只取首屏必要字段;其次把允许异步的工作放到后台执行。
@MainActor
func prepareHome() async {
state = .loading
do {
let snapshot = try await launchRepository.loadSnapshot()
state = .ready(snapshot)
} catch is CancellationError {
return
} catch {
state = .failed
}
}
底层仓库负责在正确执行上下文读取数据。页面模型不应为了看起来异步而随意创建额外队列。
六、优化首屏视图层级
首屏需要完成视图创建、约束求解和绘制。可以检查:
- 是否一次创建了首屏之外的复杂子页面。
- 是否存在大量透明叠层和复杂遮罩。
- 自动布局约束是否冲突或频繁更新。
- 图片是否远大于实际显示尺寸。
- 首页列表是否在首帧前同步构建过多单元格模型。
骨架界面应保持结构简单。为每个占位块添加独立动画,可能在启动阶段造成额外主线程和绘制压力。
七、分阶段展示数据
首屏不一定要等待所有模块同时完成。账户摘要、本地最近记录和远程推荐可以根据依赖分别加载。关键内容优先展示,非关键区域在准备好后更新。
如果本地有仍然可信的快照,可以先展示再刷新;若数据过期后可能误导用户,就应显示明确加载状态。缓存策略需要按业务风险制定,不能为了启动数字统一使用旧数据。
八、减少动态库和启动注册成本
大量动态组件会增加装载和绑定工作。项目可以定期检查依赖是否确实在使用,是否存在功能重复的库,以及只用到少量能力却引入完整组件的情况。
通知注册、路由注册和服务扫描也可能随着业务增长变得昂贵。可以生成确定注册表或按业务延迟注册,但要遵循项目现有架构,避免引入两套入口机制。
九、不要用固定等待装饰启动
为了让动画完整播放而设置固定等待,会直接增加所有用户的启动时间。动效可以与真实准备过程协调:数据提前完成时自然结束,数据尚未完成时保持稳定状态,而不是把等待写死。
同样,不应让启动页承担复杂请求和业务判断。它的主要职责是平滑衔接系统画面和真实首页。
十、建立可重复测量
测量时要固定设备、系统状态、构建配置和操作路径。多次冷启动取稳定分布,并分别记录进入 main 前后、首帧和业务可用时间。
调试构建包含额外检查,不能完全代表正式表现。优化后还要观察内存峰值和首次进入功能的延迟,避免只是把成本从启动移动到下一次点击。
总结
iOS 启动优化要围绕关键路径展开:减少静态初始化和启动回调中的同步工作,简化首屏视图,并按业务优先级分阶段加载数据。持续测量首帧和可交互时间,才能发现回归,也能防止延迟初始化制造新的卡顿。
- 点赞
- 收藏
- 关注作者
评论(0)