屏幕呈像
iOS的屏幕成像中,CPU,GPU起着关键作用,屏幕的卡顿与CPU对数据的计算,GPU的渲染,屏幕的刷新率都有关。
- CPU:对象的创建销毁,属性调整,布局计算,图片格式转换和解码,图像绘制.
- GPU:对纹理的渲染。
- 屏幕刷新
屏幕成像:上面3步中,第一步CPU完成计算后,第二部GPU进行纹理渲染。这两步是CPU完成工作后,GPU才会进行工作,而第三步和前两步是处于不同的两条线程。当前两步完成时,第三提早发送信号或者晚发送信号距CPU和GPU完成工作时间间隔较长,就会发生卡顿。
卡顿优化
优化思路,尽量减少CPU,GPU资源消耗。
- 尽量使用轻量级的对象,能使用int,尽量不使用NSInterger,NSNumber,若是view没有点击事件尽量用CALayer替代View。
- 不频繁的使用frame,bounds,transform等属性,减少不必要的修改,AutoLayout会比直接设置frame消耗的资源多。
- 图片的Size最好和image的size一样大。
- 控制线程的最大并发量。
- 尽量把耗时操作放到子线程(文本处理尺寸计算,绘制;图片解码,绘制);
- 尽量避免段时间内大量图片的显示,尽可能将多张图片合成一张显示。
- 减少视图数量和层次,减少透明的图层,不透明的就设置opaque为YES。
- 尽量减少离屏渲染(渲染模式分两种:离屏渲染,当前屏幕渲染)。
- 离屏渲染消耗性能的原因
- 需要创建新的缓冲区。
- 离屏渲染过程需要多次切换上下文:先从当前屏幕切换到离屏,等到渲染结束,将缓冲区渲染结果显示到屏幕上,又要将上下文环境从离屏切换到当前的屏幕。
触发离屏渲染的操作
- 光栅化 layer.shouldRasterize = YES;
- 遮罩 layer.mask
- 圆角 layer.masksToBounds = YES;layer.cornerRadius >0;同时设置
可以通过CoreGraphics绘制圆角,或者直接和美工要圆角图片 - layer.shadowXXX. 可以设置layer.shadowPath就不会产生离屏渲染
卡顿检测
平时说的卡顿,主要是因为在主线程中耗时操作比较多,可以添加observer到Runloop中,通过runloop切换状态的耗时,达到监控卡顿目的
耗电优化
主要耗电来源
- CPU处理
- 网络,Networking
- 定位,location
- 图像,Graphics
优化
1. 少用定时器
2. I/O优化
- 不要频繁写入小数据,最好批量一次性写入。
- 读写大量重要数据时,考虑dispatch_io, 其提供了基于GCD的异步操作文件I/O的API。用dispatch_io系统会优化磁盘访问。
- 数据量比较大的,建议使用数据库(SQLite,COreData)
网络优化
- 减少,压缩网络数据
- 如果多次请求的结果相同的,尽量使用缓存
- 使用断点续传,否则网络不稳定时可能多次传输相同的内容
- 网络不可用时,不要尝试网络请求
- 用户可以取消长时间运行或者数独很慢的网络操作,设置合适的超时时间。
- 批量传输,下载时一次性多下载内容,减少下载次数。
定位优化
- 如果只需快速确定用户位置,最好用CLLocationManager的requestLocation方法。定位完成后会让硬件断电。
- 如果不是导航应用,尽量不要实时更新位置,定位完就关掉定位服务
- 尽量降低定位精度,比如尽量不要用精度最高的kCLLocationAccuracyBest。
- 需要后台定位时,尽量设置pauseLocationUpdatesAutomatically 为YES,当用户不太可能移动时系统会自动暂停定位更新
- 尽量不要使用startMonitoringSignificantLocationChanges
硬件检测优化
用户移动,摇晃,倾斜设备时,会产生动作(motion)事件,这些事件由加速计,陀螺仪,磁力计等硬件检测,在不需要检测的场合,应及时关闭这些硬件。
启动优化
APP启动分两种
- 冷启动:从零开始启动APP
- 热启动:APP已经在内存中,在后台存活着,再次点击图标启动APP
通过添加环境变量可以打印APP的启动时间分析
Edit scheme-> Run->Arguments : DYLD_PRINT_STATISTICS_DETAILS设置为1
APP的启动分三个阶段
- dyld:Apple的动态链接器,可以用来装载Mach-0文件(可执行文件,动态库)。
- 装载APP的可执行文件,同时递归加载所有依赖的动态库
- 当dyld把可执行文件、动态库都装载完毕后,会通知Runtime进行下一步的处理
- 启动APP时,runtime做的事情
- 调用map_images进行可执行文件内容的解析和处理
- 在load_images中调用call_load_methods,调用所有Class和Category的+load方法
- 进行objc结构的初始化(注册Objc类,初始化类对象等)
- 调用C++静态初始化器和attribute(constructor)修饰的函数
- 到这里,可执行文件和动态库中的所有符号(Class, protocol, selector,IMP...)都已经按格式加载到内存中,被runtime所管理。
- 总结
- APP启动由dyld主导,将苹果的.owen文件加载到内存
- 加载动态链接库,rebase 指针调整和bind符号绑定。
- Objc的runtime的分类和类的注册,selector唯一性检查;
- Objc的runtime初始化处理 :执行load方法,attribute修饰函数调用,创建C++全局变量。
- 所有初始化工作结束后,dyld就会调用main函数。
- 最后就是UIApplicationMain函数,AppDelegate的application:didFinishLaunchingWithOptions方法。
启动优化
dyld:
- 减少动态库,合并一些动态库
- 减少Objc 类,分类的数量,减少Selector数量
- 减少C++虚函数,虚函数会增加虚表
- Load方法用 initalize代替
- Swift尽量使用struct
功能级别优化:
除首屏展示所需要的功能外,didFinishLaunchingWithOptions方法里尽量不要处理别的事情
方法级别优化:
耗时多的方法尽量放到子线程
检查耗时可以使用Time profile检查。
runtime:
- 用+initialize方法和dispatch_once取代所有的_attribute((constructor)),C++静态构造器,ObjC的+load
main: - 不影响体验前提下,尽可能将一些操作延迟,不要全部都放在finishLaunching方法中。
安装包瘦身
- 资源采取无损压缩
- 去除没有用到的资源
- 去掉异常支持:Enable C++ Exceptions、Enable Objective-C Exceptions设置为NO,other c Flags 添加 -fno-exceptions
- 检查未使用的代码。
网友评论