WWDC2012 iOS App Performance:Responsiveness 笔记

如果观看过 WWDC 2012 Session 305 - iOS App Performance: Responsiveness 可以略过本文。

首先,该篇 WWDC Session 有两个主题

  • 响应式:app 如何更快的响应用户操作
  • 性能优化:让 app 高效的运行

    一、应用启动

  • app 启动时间是第一指标
  • app 启动时会有一段过渡动画
    • iPhone 上有 400 毫秒
    • iPad 上有 500 毫秒
  • 力争更快的启动 app

iOS 系统会有一个 watchdog 来监测 app 的启动时间是否过长,根据 app 的生命周期,对应的时间阈值如下表所示:

场景 Watchdog 时间阈值
启动 Launch 20 秒
重载 Resume 10 秒
挂起 Suspend 10 秒
退出 Quit 6 秒
后台任务 Background Task 10 分钟

值得注意的是,如果是在 Xcode 中以 Debug 模式运行你的 app,这个 watchdog 机制是默认禁用的。也就是说在 Release 模式下才会激活这个机制。

1.计算 app 的启动时间

选择一个合适的节点

  • Watchdog 会监听第一次 CATranscation 事务的结束
    • 第一次布局与渲染
    • CoreAnimation 的内部方法 -[UIApplication _reportAppLaunchFinshed]
  • 用户可能关心的其它指标
    • 相机类 app 应该计算好快门开启的时间

2.记录第一次渲染的开始和结束时间

  • 在 main() 中获取渲染开始时间
1
2
int main(int argc, char **argv) {
StartTime = CFAbsoluteTimeGetCurrent();
  • 在 applicationDidFinishLaunching 中获得渲染结束时间
1
2
3
4
5
- (void)applicationDidFinishLaunching:(UIApplication *)app {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Launched in %f sec", CFAbsoluteTimeGetCurrent() - StartTime);
});
}

这里使用 GCD 的原因是在 applicationDidFinishLaunching 回调方法返回前,并不能确保 app 渲染完成了,所以需要使用异步的方式来在主线程上获取时间差。

3.使用 Time Profiler 来计算第一次渲染所耗费的时间

4.App 启动的流程

  • 链接和装载 Linking and loading
  • UIKit 初始化
  • Application 回调
  • 第一次 Core Animation 事务完成

5.App 启动总结

Launch is the first user interaction - it should be responsive
App 启动是用户的第一层交互,这个过程应该是顺滑的


Measure launch time
计算启动耗费的时间


Profile with Time Profiler
使用 Time Profiler 工具来调试


Observe best practices
遵守最佳实践

二、性能优化策略

2.1 避免不必要的工作

  • 对 App 进行 Profile 后,通常会揭露出 App 中一些不必要的模块
  • 例子
    • 不必要的阴影和遮罩
    • 对同一数据的多次请求
    • 启动时过多的日志打印会耗费很多时间

2.2 重用而不是重新创建

  • 特定的一些类的初始化是代价很高的
    • TableView 的 cell
    • 日期/数字 格式化器
    • 正则表达式
    • SQLite 语句
  • 重用这些对象而不是重新创建

2.2.1 日期格式化 Date Formatter

  • 使用日期格式化的大多数场景
    • 对于一种日期格式缓存对应的一个日期格式化器 (Date Formatter)
    • 当收到 NSLocaleDidChangeNotification 通知时,让缓存失效
  • 设置格式和重新创建都是性能高昂的操作

2.2.2 日历 Calendars

  • 每一句 NSLog 的调用都会创建一个新的 calendar 实例
    • 避免 NSLog 的过度使用
  • 通过调用 +[NSCalendar currentCalendar] 对于每个 cell 都返回一个新的实例出来
    • 如果重复使用的话应该保存这个实例

2.2.3 SQLite 语句

  • 每一条 SQLite 语句都是一个可编译程序
    • 使用 sqlite3_prepare 将 SQL 查询语句转换为字节码
  • 使用绑定参数并重用语句

2.3 高效的开发

  • 选择合适的数据结构和算法
  • 选择更快的算法

2.4 提前计算结果

2.5 异步加载

2.6 大量数据测试

leejunhui wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!