全面优化 iOS App 性能

项目刚起步的过程中,往往时间紧任务重,在开发的时候,只想着要完成开发需求,没有多余的时间去关注性能问题,而且再加上产品的需求一般是敏捷开发,改了又改,改的它亲妈都认不出来了,就呵呵呵呵了。但随着项目越来越大,功能越来多,卡顿问题越来越严重,用户体验很不好。解决卡顿的问题,刻不容缓啊,于是呢,就想多唠叨几句。

1. 性能检测的发展

移动端性能检测(简称APM)盛起于2016年,结束于2017年末。大家查相关文章就可以发现这样的规律。鼎盛期间,各个大厂都开发、开放了自己的APM平台。估计那个时候大厂都觉得这是一块热点,想部署个制高点。到现在neteasaAPM登录不进去、bugly2018年没有更新、OneAPM还在运行,但也不更新了(用起来还不错)。

  • 通过2016年、2017年两年,完成了技术挖掘&产品成熟化。成熟了,定型了,技术都突破了,没什么可以研究讨论的了。
  • 小厂对于APM并不关注,产品现能推向市场再说,能活下来再说。很少有App最后走到需要进行性能优化阶段。
  • 移动端App的红利结束,这个就不用解释了。
  • 小厂App量上不去,去看看App Store排行榜上的前300名App就知道了,都被大厂垄断了。
    而对于程序员的进化也分几个层次
    第一层:你能熟练使用合适的工具来检测App的问题,不要等问题发生了在去做准备。当然你说做完跑路,那就当我没说
    第二层:能在实际项目中用工具发现并解决问题
    第三层:知道这些工具实现的原理,并能和自己的开发流程无缝对接到一起。当然我希望你们都来这一层,那样到处都是牛逼人,和谐社会了。

2.卡顿检测:FPS及具体定位

帧率图.png

在显示器中是固定的频率,比如iOS中是每秒60帧(60FPS),即每帧16.7ms。从上图中可以看出,每两个VSync信号之间有时间间隔(16.7ms),在这个时间内,CPU主线程计算布局,解码图片,创建视图,绘制文本,计算完成后将内容交给GPU,GPU变换,合成,渲染,放入帧缓冲区。假如16.7ms内,CPU和GPU没有来得及生产出一帧缓冲,那么这一帧会被丢弃,显示器就会保持不变,继续显示上一帧内容,这就将导致导致画面卡顿。所以无论CPU,GPU,哪个消耗时间过长,都会导致在16.7ms内无法生成一帧缓存

简单来说,主线程为了达到接近60fps的绘制效率,不能在UI线程有单个超过(1/60s≈16ms)的计算任务,导致卡顿

引起卡顿的操作无非就这几个
死锁:主线程拿到锁 A,需要获得锁 B,而同时某个子线程拿了锁 B,需要锁 A,这样相互等待就死锁了。
抢锁:主线程需要访问 DB,而此时某个子线程往 DB 插入大量数据。通常抢锁的体验是偶尔卡一阵子,过会就恢复了。
主线程大量 IO:主线程为了方便直接写入大量数据,会导致界面卡顿。
主线程大量计算:算法不合理,导致主线程某个函数占用大量 CPU。
大量的 UI 绘制:复杂的 UI、图文混排等,带来大量的 UI 绘制。

其实说那么多无非就是:
解决的方案就是把控制总时间,分解开来就是看:

  • CPU的耗时在哪里了,如何解决?
  • GPU耗时在哪里了,如何解决?
    解决方案:

1.除了用第三方代码来检测,开发人员完全可以通过instruments工具来发现问题;借助instruments工具还可以分析和定位问题。
2.卡顿问题发现简单,难点在于修改问题,找合适方案。KMCGeigerCounter非常优秀的检测cpu卡顿和帧速的工具,这工具就不错;遗憾的是它只能检测CPU的下降。

#if !TARGET_IPHONE_SIMULATOR
[KMCGeigerCounter sharedGeigerCounter].enabled = YES;
#endif

3.主要介绍下OneAPM

用户的所有交互,每一次会话,甚至是划屏解锁,OneAPM 都能实时监控其性能表现。而这一切,都是为了确保你的 iOS App 能够给予用户最棒的性能体验。OneAPM 作为 iOS 应用性能管理最新的解决方案,也将协助你的应用成为 App Store 同类产品中最棒的。

用户的所有交互,每一次会话,甚至是划屏解锁,OneAPM 都能实时监控其性能表现。而这一切,都是为了确保你的 iOS App 能够给予用户最棒的性能体验。

OneAPM 作为 iOS 应用性能管理最新的解决方案,也将协助你的应用在 App Store 中脱颖而出

OneAPM iOS SDK 目前已支持 Objective-CSwift

1.追踪响应时间,优化产品性能
2.详悉错误信息,轻松定位根源问题
3.建立业务和性能的联系,方便感知业务增幅
4.以单个设备为单位度量应用性能
5.以数据库、CPU、内存性能度量设备性能表现
6.端到端的交互甘特图,给予各个事件的性能可见性
7.不同事件的性能区隔,方便快速定位性能优化点
8.识别设备类型(iPhone/iPad/iPod、操作系统版本、运营商类型),分类设备性能
9.with me OneAPM iOS SDK 3 分钟快速部署,应用性能管理从未如此简单
从现在开始使用 OneAPM 吧!快速捕捉性能表现差的应用代码,发现错误并随时向你发送警报,这一切只需下载并安装 OneAPM iOS SDK,然后更新你的应用。OneAPM 保证这一切只需 3 分钟。

4. 一分钟教程送给大家

4.1、 下载并解压 OneAPM iOS SDK

下载最新版本的 iOS SDK。在安装步骤页 (https://download.oneapm.com/ios_agent/)的第一项输入项目名称,点击提交,记下随后出现的 Token。

4.2、 添加 OneAPM Framework 至 Xcode 项目中

解压 SDK,并将「OneAPM.framework」文件夹从 Finder 中拖拽至 Xcode 项目中(悬停至导航窗口的项目中)。出现提示窗口时,选择「Copy items into destination…」和「Create folder references…」。

4.3、 在 Linker Settings 中添加以下 5 个 Libraries

在项目导航窗口内点击你的 Project,并选中你的 App,然后选择「Build Phases」选项卡。打开「Link Binary with Libraries」列表。点击添加:

•   SystemConfiguration.framework
•   CoreTelephony.framework
•   CoreData.framework
•   libz.dylib
•   libstdc++.dylib 


4.4、启动 SDK

• 在项目文件 [app_name]-Prefix.pch(通常在文件夹「Support Files」中)中,引入 OneAPM 头文件:

#import   

• 在文件 AppDelegate.m 中添加如下代码,并确保它在

application:didFinishLaunchingWithOptions

的第一行中。

[OneAPM startWithApplicationToken:@""];

4.5、运行应用程序

Clean Project,并重新在模拟器或设备中启动应用程序,开始应用性能管理。

4.6、 重启

请静候 1分钟,等待应用程序向 OneAPM 发送应用程序性能数据,即可开始使用 OneAPM 应用性能管理功能。

5. 最后再补充一个知识点(CADisplayLink与NSTimer区别)

既然CADisplayLink也是一个定时器,那么两者有什么区别与联系呢?

5.1、原理不同

CADisplayLink是一个能让我们以和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息,CADisplayLink类对应的selector就会被调用一次。
NSTimer以指定的模式注册到runloop后,每当设定的周期时间到达后,runloop会向指定的target发送一次指定的selector消息。

5.2、周期设置方式不同

iOS设备的屏幕刷新频率(FPS)是60Hz,因此CADisplayLinkselector默认调用周期是每秒60次,这个周期可以通过frameInterval属性设置,CADisplayLinkselector每秒调用次数=60/frameInterval。比如当frameInterval设为2,每秒调用就变成30次。因此,CADisplayLink周期的设置方式略显不便。
NSTimerselector调用周期可以在初始化时直接设定,相对就灵活的多。

5.3、精确度不同

iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。
NSTimer的精确度就显得低了点,比如NSTimer的触发时间到的时候,runloop如果在忙于别的调用,触发时间就会推迟到下一个runloop周期。更有甚者,在OS X v10.9以后为了尽量避免在NSTimer触发时间到了而去中断当前处理的任务,NSTimer新增了tolerance属性,让用户可以设置可以容忍的触发的时间范围。

5.4、使用场合

从原理上不难看出,CADisplayLink使用场合相对专一,适合做界面的不停重绘,比如视频播放的时候需要不停地获取下一帧用于界面渲染。
NSTimer的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用。

你可能感兴趣的:(全面优化 iOS App 性能)