安装包优化
1. 资源(图片、音视频等)
2. 采用无损压缩
3. 删除没有用到的资源
4. Strip Linked Product、Make Strings Read-Only、Symbols Hidden by Default设置为YES
5. 去掉异常支持,Enable C++ Exceptions、Enable Objective-C Exceptions设置为NO, Other C Flags添加-fno-exceptions
6. 利用APPCode检测未使用的代码
7. 利用LLVM插件检测出重复代码、未调用代码
参考:
iOS 脚本查看项目未使用到的方法 - 检测哪些方法未使用
脚本方法只能检测OC 可能未使用的方法,不适用其他场景。
python 依赖 otool 作为工具,原理利用 Mach-O 文件的结构和展示内容。
__TEXT:__objc_methname: 中包含了代码中的所有方法
__DATA__objc_selrefs中 则包含了所有被使用的方法的引用。通过取两个集合的差集就可以得到所有未被使用的代码。
iOS 清除项目中未使用的类和图片 (APP安装包瘦身) -
iOS实时卡顿检测-RunLoop_gcs的博客-CSDN博客 代码卡顿检测
iOS卡顿监测方案总结 - CocoaChina_一站式开发者成长社区
卡顿优化
1:CPU
1.1: 尽量使用轻量级对象,比如用不到事件处理的地方,可以考虑使用CALayer取代UIView
1.2:不要频繁调用UIView的相关属性,比如frame、bounds、transform等属性,尽量减少不必要的修改
1.3:尽量提前计算好布局,在有需要时一次调整,不要多次修改属性
autolayout比直接设置frame消耗更多CPU资源,因为最终还是要转化成frame 的形式。
1.4:图片的size最好刚好跟UIImageView的size一样
1.5:控制一下线程最大并发数。尽量把耗时操作放到子线程
1.6:文本处理(尺寸计算、绘制),做好预排版处理
1.7:图片处理(解码、绘制),串行队列,图片单张解码,避免高清大图内存暴增引起的内存耗尽crash
2: GPU
2.1: 尽量减少短时间内的图片大量显示,尽可能的合成一张图片显示
2.2:GPU最大能处理的纹理是4096 x 4096,一但超过这个尺寸,就需要占用CPU资源处理,所以纹理最好不要超过这个尺寸
2.3:尽量减少视图的数量和层次
2.4:尽量不要使用透明度,GPU 计算混合颜色时较为复杂,耗时
2.5:尽量不要出现离屏渲染(在当前屏幕缓冲区以外,开出一片新的缓冲区进行渲染操作)
需要创建新的缓冲区
离屏渲染需要多次切换上下文,先从当前屏幕,切换到离屏屏幕,等到离屏渲染完成之后,有需要将缓冲区渲染到当前屏幕,有需要将上下文环境从离屏屏幕切换到当前屏幕
那些操作会造成离屏渲染
光栅化,layer.shouldRasterize = YES; 计算工作会转移到cpu
遮罩,layer.mask
圆角,同时设置layer.masksToBounds = YES 和 layer.corner > 0,可以考虑通过CoreGraphics绘制剪裁圆角,或直接使用圆角图片
阴影,layer.shadowXXX,如果设置了layer.shadowPath就不会产生离屏渲染
参考: iOS-卡顿优化,图片绘制渲染,压缩
卡顿检测
方案1. FPS (Frames Per Second) 是图像领域中的定义,表示每秒渲染帧数,通常用于衡量画面的流畅度,每秒帧数越多,则表示画面越流畅,60fps 最佳,一般APP的FPS 只要保持在 50-60之间,用户体验都是比较流畅的。
监测FPS也有好几种,这在YYFPSLabel中看到的。 实现原理实现原理是向主线程的RunLoop的添加一个 commonModes 的 CADisplayLink,每次屏幕刷新的时候都要执行CADisplayLink的方法,所以可以统计1s内屏幕刷新的次数,也就是FPS了.
方案2. FPS中CADisplayLink的使用也是基于RunLoop,都依赖main RunLoop
可以看到RunLoop调用方法主要集中在 kCFRunLoopBeforeSources和kCFRunLoopAfterWaiting 之间,大部分导致卡顿的的方法是在kCFRunLoopBeforeSources和kCFRunLoopAfterWaiting 之间.
source0 主要是处理App内部事件,App自己负责管理(出发),如UIEvent(Touch事件等,GS发起到RunLoop运行再到事件回调到UI)、CFSocketRef。
方案:开辟一个子线程,然后实时计算 kCFRunLoopBeforeSources ,kCFRunLoopBeforeWaiting,kCFRunLoopAfterWaiting 两个状态区域之间的耗时是否超过某个阀值,来断定主线程的卡顿情况。
可以设置连续5次超时50ms认为卡顿,戴铭在GCDFetchFeed中设置的是连续3次超时80ms认为卡顿的代码。
方案3.:子线程Ping
由于主线程 RunLoop 在闲置时基本处于Before Waiting状态。导致即便没有发生任何卡顿,方案2的检测方式也会认定主线程处在卡顿状态。
思路:创建一个子线程通过信号量去ping主线程,因为ping 的时候主线程肯定是在kCFRunLoopBeforeSources 和 kCFRunLoopAfterWaiting之间。每次检测时设置标记位为YES,然后派发任务到主线程中将标记位设置为NO。接着子线程沉睡超时阙值时长,判断标志位是否成功设置成NO,如果没有说明主线程发生了卡顿。ANREye中就是使用子线程Ping的方式监测卡顿的。