iOS 性能优化_微博优化技巧

最近研究了一下微博,发现微博列表中可以优化的点相当多,先将比较容易优化的点罗列如下:

  1. 预排版
    当获取到 API JSON 数据后,将每条 cell 需要的数据都在后台线程计算并封装成一个布局对象 cellLayout。cellLayout 包含有所有文本的 CoreText 排版结果、cell 内部每个控件的高度、cell 整体的高度。每个 cellLayout 占用的内存并不多,所以当生成后,可以全部缓存到内存,以供稍后使用。这样,tableView 在计算各个 cell 高度时,将不会消耗任何多余的计算量;当把 CellLayout 设置到 cell 内部时,cell 内部也就不用再计算布局了。
    对于通常的 tableView 来说,提前在后台计算好布局结果是一个非常重要的性能优化点。为了达到最高性能,可能会牺牲一些开发速度,不要使用 AutoLayout 等技术,少用 UILabel 等文本控件。如果你对性能的要求并不那么高,可以尝试使用 TableView 的预估行高功能,并把每个 cell 高度缓存下来。这里有个百度知道团队的开源项目可以很方便的帮你实现这一点:FDTemplateLayoutCell.

  2. 预渲染
    微博的头像在某次改版中换成了圆形,当头像下载下来后,在后台线程将头像预先渲染为圆形并单独保存到一个图片缓存队列中去。
    对于 tableView 来说,cell 内容的离屏渲染会带来较大的 GPU 消耗。使用 layer 的圆角属性在低性能的设备上快速滑动的时候,尽管没有感觉到较大的卡顿,但整体的平均帧数降了下来。用 Instument 查看的时候可以看到 GPU 已经满负荷运转,而 CPU 却比较清闲。为了避免离屏渲染,应当尽量避免使用 Layer 的 border、corner、shadow、mask 等技术,而尽量在后台线程预先绘制好对应的内容。

  3. 异步绘制
    参考 ASDK 的实现原理,实现了一部分简单异步绘制的代码:YYAsyncLayer。YYAsyncLayer 是 CALayer 的子类,当它需要显示内容(比如调用了[self setNeedDisplay])的时候它会向代理,也就是 UIView 请求一个异步绘制的任务。在异步绘制的时候,Layer 会传递一个 block 回调,绘制代码可以随时调用该 block 判断绘制任务是否被取消。
    当 tableView 快速滑动的时候,会有大量的异步绘制任务提交到后台线程去执行,但是滑动速度过快的时候绘制任务还没有完成就已经被取消了,这时候如果继续绘制,就会造成大量的 CPU 资源浪费,甚至阻塞线程并造成后续的绘制任务迟迟无法实现,这样我们就需要尽量快速、提前判断当前绘制任务是否被取消,保证被取消的任务能及时退出,不至于影响后续操作。
    目前有些第三方微博客户端,使用了这样一种方法来避免高速滑动时候 cell 的绘制过程,相关实现见这个项目VVeboTableViewDemo.它的原理是,当滑动时,松开手指后,立刻计算出滑动停止的时候 cell 的位置,并需要绘制那个位置附近的几个 cell,而忽略当前滑动中的 cel。这个方法比较有技巧性,并且对于滑动性来说是很大的提升,唯一的缺点是快速滑动过程中会出现大量空白的内容。如果你不想实现比较麻烦的异步绘制而又想保证滑动的流程性,这个技巧是不错的选择。

  4. 全局并发控制
    当使用 concurrent queue 来执行大量绘制任务的时候,偶尔会遇到这种问题:



大量的任务提交到后台队列的时候,某些任务会因为某些原因(此处是 CGFont锁)被锁住导致线程休眠,或者被阻塞。concurrent queue 随后会创建新的线程来执行其他任务。当这种情况多变时,或者 App 中使用了大量 concurrent queue 来执行较多任务时,App 在同一时刻就会存在几十个线程同时运行、创建、销毁。CPU 是用时间片轮转来实现线程并发的,尽管 concurrent queue 能控制线程的优先级,但大量线程同时操作的时候,这个操作仍然会挤占掉主线程的 CPU 资源。ASDK 有个 Feed 列表的 Demo:SocialAppLayout,当列表内 cell 过多,并且非常快速的滑动的时候,界面仍然会出现少量卡顿,就是这个原因造成的。
使用 concurrent queue 时不可避免的会遇到这种问题,但当使用 serial queue 又不能充分发挥多核 CPU 资源,有一个简单的工具: YYDispatchQueuePool 为不同优先级创建和 CPU 数量相同的 serial queue ,每次从 pool 中取 queue 的时候,会轮询返回其中的一个 queue。可以把 App 内所有的异步操作,包括图像解码、对象释放、异步绘制等,都按照优先级的不同放入了全局的 serial queue 中执行,这样尽量避免了过多线程导致的性能问题

  1. 更高效的异步图片加载
    SDWebImage 有时候仍然会产生少量的性能问题,并且有地方不能满足需求,所以这时候需要实现一个性能更高德图片加载库。在显示单张图片的时候,利用 UIView.layer.contents 就足够了,没有必要使用 UIImageView 带来额外的资源消耗,为此可以在 CALayer 上添加 setImageWithURL: 等方法。除此之外,还可以把图片解码等操作通过 YYDispatchQueuePool 进行管理,控制 App 总线程数量。

  2. 其它可以改进的地方

  3. 列表中不需要响应触摸事件的控件可以事先用 ASDK 的图层合成技术预先合为一张图,

  4. 进一步减少每个 cell 内部图层的数量,用 CALayer 替换掉 UIView。

  5. 将 cell 按类型划分,进一步减少 cell 内部不必要的视图对象和操作

  6. 把需要放到主线程的任务划分为足够小的块,并通过 Runloop 来进行调度,在每个 loop 中判断下一次 Vsync 时间,并在下次 Vsync 到来之前,把当前未执行完的任务延迟到下一个循环中去。

  7. 如何评测界面的流畅度
    过早的优化是万恶之源,在需求未定、性能问题不明显时,没有必要尝试进行优化,而是要尽量正确的实现功能。在做性能优化的时候,也最好走 修改代码->profile->修改代码这样一个流程,优化最值得优化的地方。
    如果你需要一个明确的 FPS 指示器,可以尝试一下 KMCGeigerCounter,对于 CPU 的卡顿,它可以通过内置的 CADisplayLink 检测出来;对于 CPU 带来的卡顿,它用了一个1X1 的 SKView 来进行监视。这个项目有两个小问题:SKView 虽然能监视到 GPU 的卡顿,但是引入 SKView 本身就会对 CPU/GPU 带来一些额外的资源消耗;而且这个项目在 iOS 下会有一些额外的兼容问题。
    这个 FPS 指示器 YYFPSLabel 虽然只有几十行代码,仅用到了 CADisplayLink 来监视 CPU 的卡顿问题,但是可以满足日常需要。
    最后使用 Instument 的 GPU Driver 预设,能够实时查看到 CPU 和 GPU 的资源消耗。早这个预设内,你可以看到所以与现实有关的数据,比如 Texture 数量、CA 提交的频率、GPU 消耗等,在定位界面卡顿的问题的时候,这是最好的工具。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容