30. 启动优化
启动优化的目标是“冷启动更短、首屏更快、任务更少”。关键是分清启动链路与非关键任务。
一、冷启动链路
- App 启动
- 加载动态库
- 执行
main application(_:didFinishLaunchingWithOptions:)- 创建首屏
二、启动耗时统计
1. 使用时间戳
let launchStart = CFAbsoluteTimeGetCurrent()
func recordLaunchEnd() {
let end = CFAbsoluteTimeGetCurrent()
print("Launch time: \(end - launchStart)")
}
2. 使用 Signpost
import os.signpost
let log = OSLog(subsystem: "com.jj.app", category: .pointsOfInterest)
let signpostID = OSSignpostID(log: log)
func markLaunchBegin() {
os_signpost(.begin, log: log, name: "Launch", signpostID: signpostID)
}
func markLaunchEnd() {
os_signpost(.end, log: log, name: "Launch", signpostID: signpostID)
}
三、拆分启动任务
1. 必须任务
- 基础配置
- 崩溃上报初始化
- 首屏数据准备
2. 可延迟任务
- 日志/统计 SDK
- 远程配置拉取
- 大型缓存加载
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
setupEssential()
DispatchQueue.global().async {
setupAnalytics()
preloadCache()
}
return true
}
四、减少主线程阻塞
- 避免同步 IO
- 不在启动阶段做大 JSON 解析
- 图像解码异步处理
DispatchQueue.global().async {
let data = try? Data(contentsOf: url)
DispatchQueue.main.async {
// 更新 UI
}
}
五、减少动态库与加载成本
- 能静态的尽量静态
- 删除未使用的依赖
- 合并小型库
六、首屏渲染策略
- 先渲染骨架屏
- 数据到达后刷新
- 保证首屏快速可见
func showSkeleton() {
// 先显示占位视图
}
func renderContent() {
// 数据返回后更新
}
七、持续优化的方法
- 记录每次版本的启动耗时
- 对关键版本做对比分析
- 明确启动指标目标(如 1.5s 以内)
启动优化是一条长期工程线,拆分与监控是关键。