UITableView滚动流畅性的优化

影响UITableView滚动的流畅性优化的原因

1、在代理方法中做了过多的计算占用了UI线程的时间

2、cell中view的组织复杂;eg:使用layer并不会有太大影响,但是layer层如果使用了透明、圆角、变形等效果,就会影响到绘制速度;

在代理方法中做了过多的计算占用了UI线程的时间

关于第一点首先要明白 tableView的代理的调用顺序

1、通过代理设置行数 number of rows


2、通过代理没行设置行高度 heightForRoeAtIndexPath

3、通过代理设置当前屏幕可见的元素 cellForRowAtIndexPath(实测显示4寸屏的手机会取屏幕显示数量+2,3.5寸屏幕同4寸数量,虽然3.5寸屏幕可显示的cell的数量要小于4寸)

4、绘制cell 

关于第一点,首先要明白tableView的代理(这里是指datasource 和 delegate 的那套代理方法,下同方法的调用顺序和时机。对于一般的应用会有如下的顺序呢:

1、向代理要  number of rows.

2、对于每行向代理要 heoght For Row At IndexPath

3、向当前屏幕要可见的cell For Row At IndexPath(实测显示4寸屏的手机会取屏幕显示数量 +2, 3.5 寸屏幕同4 寸屏幕数量,虽然 3.5 寸可显示的 cell 数量要小于 4 寸屏)

4、然后 cell 就显示出来了

tableView:heig htForRowAtIndexPath:

很多人把优化重点放到了 cell for row at indexPath 那个代理方法里了,在这里尽可能的少计算,但是却忽略了另一个很轻松就能提升加载速度的方法:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

tableView在每次 reload data 时都会要所有cell的高度!这就是说你有100 行 cell 。走100 次这个代理方法来设置cell 的高度,而不是当前屏幕显示的cell 的数量的高度,虽然在 iOS7下多了计算 cell 的高度的 方法,但是减少计算高度时的时间,对于提升加载tableView的速度有非常明显的提高

-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath(iOS7专用)

但是有人说了“我早听人说了,reloadData方法尽量不要调用,我插入新行都用insertRowAtIndexPaths:WithROwAnimation: 删除也用delegate那个,这个中性了吧?”;这样也不能忽略heightForRowAtIndexPath 这个回调的重要性,因为在每次删除或者插入一行后同样也要调用以便返回所有行的这个回调方法!是所有行!你没有看错,所有所以只需减少一个代理方法的计算量,就可以明显的提升加载速度。

对于减少tableView:heihghtForRowAtIndexPath:计算量,就尽量让这个方法的计算计算复杂度为O(1);就是只是简单的从数组中取出一个值,然后返回!

也许有人要问了,我们的应用都是动态的高度,就像微博那样的,不定数量的文字,还有图片,大小也不固定,这些怎么返回固定的高度啊?


我指的固定高度并不是row的高度都一定那种固定,而是让在tableView:heightForRowAtIndexPath:这个回调里取这个高度的时间是近乎固定的

对于高度的计算,还有个小细节需要注意,就是入如果row 的高度都一定,那么就删除tableView:heightForRowAtIndexPath:这个方法,设置tableView的rowHeight属性,相似的numberOfRowsInSection:系列的方法,我就不写出来了,苹果文档里写这样做可以减少调用时间。

现在回归正题,对于cell的高度不固定,传统的方法是为cell写个计算行高的类方法,传入那些动态的元素(文字、图片等)然后返回计算的高度。在tableView:hieghtForRoeAtIndexPath:中调用这个方法,填入需要的参数计算cell高度。这当然没有什么问题,只是要是计算量很复杂,你每次reoadData,光计算行高就花去rowCount *单行高评价计算时间 ,想想有100行,你不定期的要reloadData 或者 insert(delete)row ...... 结局办法就是:

   用空间换时间

将计算行高的时间提前到从服务器请求会数据的时候,计算完了高度一并写回数据库 ,别告诉我你在你在主线程里阻塞式的处理网络请求。。。。。。面壁思过去吧,别浪费了 GCD,NSOPerationQueue的青春。最先想到的还是NSThread同学,证明你已经老了。。。现在几乎大部分的多线程操作都不需要NSThread和Runloop了

tableView:cellForRowAtIndexPath:

说完了计算cell的行高的优化,现在来谈 tableView:cellForRowAtIndexPath: 回调的优化。优化思路同上,也是通过预处理来减少这个回调中的计算时间。这个回调重点谈的是对图片异步加载的优化

图片异步加载无非就是在这个方法里发起异步请求,图片加载完成后根据 UIImageView 的引用设置时间。有经验的程序员可能会使用懒加载的方式减少快速滑动时由于网络请求过于频繁与切换线程显示图片造成的卡顿。这里还有个问题,拿回来的图片一定和最后显示的大小不一样,有时候偷懒,直接设置imageView 的contentMode 属性为 imageView自己”压缩“,这是一个很取巧的方法,但是 tableView 的滚动速度也会造成不容忽视的影响。对图片变形需要对图片做 transForm,每次变换图片都要对图片乘以一个变幻矩阵,如果你的图片很多,计算量是不可忽视的。

        优化建议:从网络请求回来的图片先根据需要显示的图片大小切成合适大小的图,每次只显示处理过的大小的图片,当查看大图时再显示大图。如果服务器能但会处理好的大图和图片的大小更好。

使用Instrument 的 Core Animation 模板可以查看图片的压缩情况。

        Instrument 中的 Core Animation 模板只有在调试真机时才有,调适模拟器上的应用没有这个模板!!!但是可以再模拟器的Debug菜单下找到这些调适选项、

切记:调适应用性能一定要用真机,Mac 的性能完爆 iPhone,所以不要说我的应用在模拟机上调适不卡啊! 模拟器只是模拟iOS 软件的运行环境,不能模拟硬件性能!

Color Misaligned Images 这些选项对设备的所有应用有效,也就是你不需要选择 target 就能调适它(方便竞品分析:)

对于 MisAligned Images 会有两种颜色:一种是洋红色,一种是黄色、

Misaligned Images 洋红色是因为像素没对齐,比如上面的label。一般情况下是因为像素没对齐。需要抵抗锯齿,像素会出现模糊的现象。

        解决办法:在设置 view 的 frame 的时候,在高分屏避免出现21.3,6.7这样的小数,尤其是x,y坐标,用ceil 或 floor 或 round 取整。每 0.5 个点对应一个 pixel,o.3,0.7这样就难为iPhone 了。低分屏不要出现小数


黄色是因为显示的图片实际大小与显示大小不同,对图片进行了拉伸,测试显示使用 imageView 显示实际大小的图也会变黄。

     减少洋红色和黄色可以提升滚动的流畅性

手动 Drawing 试图提升流畅性

如果通过上面的方法,滚动速度还不能达到可以容忍的速度,那就只剩下最后y一个方法了:手动绘制视图

手动绘制方法,不是直接子类化UITableViewCell ,然后覆盖drawRect:方法,这样你会得到一个大黑块! 因为cell 中不是只有一个 contentView。 如果不了解 cell 的层次结构,可以去 Reveal 去看下。

绘制cell 不建议使用 UIView ,建议使用 CALayer, UIView 的绘制是建立在 CoreGraphic上的,使用的是CPU。 CALAyer 使用的是 Core Animation,CPU,GPU通吃,有系统决定使用哪个。 View 的绘制是自下向上的一层一层的绘制,然后渲染; layer 处理的是 Texure, 利用 GPU 的 Texture cache 和独立的浮点数计算单元加速纹理的处理

问题已解: 在UIView 的 drawRect 里使用 CG开头的绘图命令只是触发的伪离屏渲染,绘图还是靠 CPU 同步的在主线程绘制,在 layer 中触发的 离屏渲染会触发真正的离屏渲染,在一个独立的进程里绘制。

https://lobste.rs/s/ckm4uw/a_performance-minded_take_on_ios_design/comments/itdkfh

GPU 不喜欢透明,所以所有的图一定要弄成不透明,

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

推荐阅读更多精彩内容