我在开发iOS的过程中,逐渐形成了一些对iOS性能优化的认识,准备总结出来。恳请各位斧正。
在我的眼中,app的性能就像是app运行开发中的货币。我们开发者就像一个组织者,手机本身的性能就是可以提供给我们的演出费用,手机版本就像舞台。 出现了新的可以增加性能的技术的时候,我们就要想办法多弄点钱;有些演员价钱过高,我们要考虑是否换个人;有的设备过于陈久了,我们要考虑是否优化或者更换;为了得知哪些地方花的过多了,我们则需要想办法去监控花钱的过程。性能优化到最后的结果,就仿佛在有限的资金支持下,给观众表演出一场精彩的、没有失误的戏剧。
优化有几个关键点要记住
- 不要过早的优化 一方面,现在iOS平台的性能都普遍较好,如果花费过多的精力过早的优化,可能会影响当前的开发任务.
- 不要过度的优化 我这里举一个我曾经犯过的错误。我曾经遇到过一个实现高精度倒计时的任务,我在考察的过程中,发现了相对高精度的GCD倒计时是使用select函数来实现的。我就比较“丧心病狂”的用select函数实现了一个倒计时的单例,但是最后应用的时候发生了许多危险的多线程错误。事情到了最后还是乖乖的选择了GCD作为我的高精度倒计时实现方案。
- 重视多角度性能监控 不言而喻,只有真正的面对到了真实发生的性能问题,我们才能针对性的做出优化,而不是浪费时间在并不重要的地方。
- 尽量减少性能监控影响 我们在使用性能监控工具的时候,往往性能监控工具本身就会影响到性能。这就仿佛是一种“观察者效应”。我们要减少这种可能危险。
- 平衡各种性能优化 app的性能有很多种类。我们要明白,我们的目标是给观众表演出一场精彩的、没有失误的戏剧。但是在真正的场景中,由于很多客观原因,比如说手机版本过老(舞台太陈旧),手机性能不足(钱也少了),总是要做出各种各样的权衡,舍弃到某些地方的金钱支持(优化),以达到整体演出的完整。
- 理解优化过程的内部底层实现机制 假如你不知道app的启动过程是分为main()之前和之后两个过程,可能你一直优化mian()之后的部分,确收效甚微;假如你不知道一个view创建展示出来的过程,CPU,GPU,runloop在其中的作用,你很难做到如丝般顺滑。假如比不知道在NSSet/NSDictionary中,底层实现了hash,你可能就无法选择正确的集合去收集数据。
我们要优化那些方面
假设我们开发了一个app,我们需要优化方面?为了得知需要优化的方面,需要我们做那些监控?下面我们就简单的说几个,欢迎补充。
1.启动时间优化和监控 app的第一次打开,冷启动,热启动,app升级后启动等等。都是可以优化的点。这里我们一般着重优化第一种情况,一般而言,优化了首次启动后,对后者都有优化效果,不过我们有时还是要针对业务场景进行相应的优化。
2.app包大小的优化 App size是一项很关键的指标,现在很多巨型应用超过100M的比比皆是。在包大到一定程度之后只能通过WIFI下载,即使可以使用蜂窝网络下载,也会让人十分心疼流量。我们这时候就要分析ipa包的大小。去除无用图片,无用代码,更换图片格式,检查引用第三方库,合并类似方法等等方法。
3.网络优化 合并接口,选择合适的协议,优化 SSL 握手之前过程,优化 SSL 握手过程,优化 SSL 握手之后过程等等。
4.页面打开过程优化 我们从上一个页面进入下一个页面的时候,会经过转场动画、下载数据、绘制图片等过程。为了让用户使用起来方便,我们需要对其中的每一步都进行优化。
5.数据读写优化 这里针对的面很多,数据库的读写,集合类的选择和读写,都是属于这一类的。
6.UI卡顿优化 这个实际上是种种卡顿的集合,也是相对而言内容最多的一部分,我们需要结合实际状况来优化。
7.内存优化 避免内存爆炸,避免因内存过大被杀死,避免循环引用等等。
8.线程优化 这个算不算是优化我还有些疑虑,但是出于很多优化方案都要多线程的方式去解决。我就把它放到了这里。这里与其说是优化,更不如说是我们实际操作中需要注意的一些情况。比如说,UI的创建和刷新一定要在主线程,DB 操作、日志记录、网络回调都在各自的固定线程,合理的创建线程,并及时回收等等。
9.耗电优化 耗电的优化我们可以放到最后来说。想对而言,再解决了以上的优化之后,耗电往往也能得到优化。并且,这一项也是用户不怎么在乎的,我们可以放到最后来优化。
监控
对app的相关指标的监控和记录至关重要,我把这分为三种:
1.开发中实时监控 我们在开发中往往写入很多bug,在开发过程中直接报告我们的bug显得至关重要。我之前为了解决这个这个方案,实现了一个悬浮在app最上层的一个可以滑动的小按钮,实时展示FPS,并将内存泄露监控,卡顿监控,内存爆炸监控等等工具放入其中,在打包过程中再将其从工程中扔出即可。这样当时我们在开发的过程中就可以随时的进行修改,当然,这个本身也会带来一些副作用,但是利远远大于弊。我接下来的工作就是准备将它开源出来。
2.日志系统 有些线上发生的错误,比如说应用被杀死,应用卡顿,应用崩溃等等。我们需要一些工具来将其记录下来并发送给我们。我们可以选择一些第三方应用,但是在可以的情况下,还是采用自己开发的工具为好。这里我有一个惨痛的教训:最好是采用mmap的方式存储数据。这个我会在未来的文章中解释为什么如此让我记忆深刻。
3.埋点 埋点相对而言更适合统计用户操作等等。但是可能起到监控的作用。这里我推荐采用AOP的方式来进行无痕埋点,减少对业务代码的侵入。
总结
随着时间的推移,问题总是会被我们遇到的,也总是会遇到性能的平静,我们需要想出办法,开发出一些辅助工具来帮助我们定位、解决问题。
提个问题
现在有一个新活动页面,页面里有个tableview,每个cell都有活动倒计时。我们改从那些方面来优化,以达到点击进入页面后的顺滑。