影响 UITableView 滚动的流畅性的原因
1、 在代理方法中做了过多的计算占用了 UI 线程的时间
2、同上
3、Cell 中 view 的组织复杂
关于第一点,首先要明白 tableview 的代理(这里指 datasource 和 delegate 的那套方法,下同)方法的调用顺序,和时机。对于一般的应用会有如下顺序:
1、向代理要 number Of Rows。
2、对于每行向代理要 height For Row At Index Path。
3、向代理要 当前屏幕可见的 cell For Row At Index Path 。(实测显示4寸屏的手机会取 屏幕显示数量+2,3.5寸屏同4寸屏数量,虽然3.5寸屏可显示的cell 数量要小于 4寸屏!)
4、然后 cell 就显示出来了。
tableView:heightForRowAtIndexPath:
很多人都把优化的重点放到了 cell for row at indexpath 那个方法里了,在这里尽可能的少计算,但是却忽略了另一个很轻松就能提升加载时间的方法 :
- - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
Table View 在每次 reload data 时都会要所有 cell 的高度!这就是说你有一百行 cell,就像代理要100次每个cell 的高度,而不是当前屏幕显示的cell 的数量的高度!虽然在 iOS 7 下多了计算 cell 高度的方法,但是减少 计算高度时的时间,对于提升加载 Table View 的速度有非常明显的提高!
- - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
- (**iOS 7专用**)
但是有人说了,我早听别人说了,reloadData 方法尽量不要调用,我插入新行都用 insertRowsAtIndexPaths:withRowAnimation: 删除也用 delete 那个,这个总行了吧?!
这样也不能忽略 height For Row At Index Path 这个回调的重要性。因为在每次插入或者删除一行后同样需要调用一遍 所有行 的这个回调方法!是所有行!你没看错,所有只是简单的减少一个代理方法的计算量,就可以明显的提升加载速度。
对于提升 tableView:heightForRowAtIndexPath: 计算量,就是尽可能的让这个方法的计算复杂度为 O(1),就是只是简单的从数组中取一个值,然后返回!
也许有人又要问了,我的应用都是动态的高度,就像微博那样的,不定数量的文字,可能还有图片,大小也不固定,这些怎么返回固定的高度啊?
我指的固定高度不是 row 的高度都一样那种固定,而是让在 tableView:heightForRowAtIndexPath: 这个回调里取这个高度的时间是近乎固定的。
对于高度的计算,还有个小细节需要注意,就是如果 row 的高度都一定,那就删除代理中的这个 tableView:heightForRowAtIndexPath: 方法,设置 Table View 的 rowHeight 属性,相似的 numberOfRowsInSection: 系列的方法,我就不都写出来了。苹果的文档里介绍这样也可以减少了调用时间。
现在回归正题。对于 cell 高度不固定的,传统的方法是为 cell 写个计算行高的类方法,传入那些动态的元素(文字,图片等),然后返回计算后的高度。在 tableView:heightForRowAtIndexPath: 中调用这个方法,填入需要的参数计算cell 高度。这当然没有什么问题,只是要是计算量很复杂,你每次 reloadData ,光计算行高就要花去 rowCount * 单行高评价计算时间,想想有100行,你不定期的需要 reloadData 或者 insert(delete) row......解决办法就是:
用 “空间换时间”
将计算行高的时间提前到从服务器搂回数据的时候,计算完了高度一并写回数据库,别告诉我你在主线程里阻塞式的处理网络请求。。。。面壁思过去吧,别浪费了 GCD,NSOperationQueue的青春。最先想到的还是 NSThread 的同学,证明你已经老了。。。现在几乎大部分的多线程操作都不需要用到 NSThread 和 runloop了。
tableView:cellForRowAtIndexPath:
说完了计算 cell 行高的优化,现在来谈 tableView:cellForRowAtIndexPath: 回调的优化。优化思路同上,也是通过预处理减少在这个回调中的计算时间。这个回调重点谈的是对图片异步加载的优化。
图片异步加载无非就是在这个方法里发起异步请求,图片加载完后根据 UIImageView 的引用设置图片。有经验的程序员可能会使用 懒加载 的方式减少快速滑动时因为网络请求过于频繁与切换线程显示图片造成的卡顿。这里还有个问题,拿回来的图片一定和最后显示的大小不一样,有时候偷懒,直接设置 image view 的 contentMode 属性要 image view 自己 压缩。这是一个很取巧的方法,但是对 table view 的滚动速度也会造成 不容忽视 的影响。对图片变形需要对图片做 transform ,每次压缩图片都要对图片乘以一个变换矩阵,如果你的图片很多,这个计算量是不同忽视的。
优化建议:从网络搂回来图片后先根据需要显示的图片大小切成合适大小的图,每次只显示处理过大小的图片,当查看大图时在显示大图。如果服务器能直接返回预处理好的小图和图片的大小更好。
使用 Instrument 的 Core Animation 模板可以查看图片的压缩情况。如图:
Instrument 中的 Core Animation 模板只有在调试真机时才有,调试模拟器上的应用没有这个模板!!!但是可以在模拟器的 Debug 菜单下找到这些调试选项。
切记:调试应用性能一定要用真机,Mac 的性能完爆 iPhone,所有不要说我的应用在模拟器上调试时不卡啊!模拟器只能模拟 iOS 软件的运行环境,不能模拟硬件性能!
这些选项对设备的所有应用有效,也就是说你不需要选择 target 就能调试 它(方便竞品分析 :)!
对于 Misaligned images 会有两种颜色:一种是洋红色,另一种是黄色。
洋红色是因为像素没对齐,比如上面的 label,一般情况下因为像素没对齐,需要抗锯齿,图像会出现模糊的现象。
解决办法:在设置 view 的 frame 时,在高分屏避免出现 21.3,6.7这样的小数,尤其是 x,y坐标,用 ceil 或 floor 或 round 取整。每 0.5 个点对应一个 pixel,0.3,0.7这样的就难为 iPhone 了,低分屏不要出现小数。
黄色是因为显示的图片实际大小与显示大小不同,对图片进行了拉伸,测试显示使用 image view 显示实际大小的图也会变黄。
减少洋红色和黄色可以提升滚动的流畅性
手动 Drawing 视图提升流畅性
如果通过上面的方法,滚动速度还不能达到可以容忍的速度,那就只剩下最后一个办法了,手动绘制视图。
手动绘制方法,不是直接子类化 UITableViewCell,然后覆盖 drawRect: 方法,这样你会得到一个大黑块!因为 cell 中不是只有一个 content view。如果不了解 cell 的层次结构,可以用 Reveal 去看下。
绘制 cell 不建议使用 UIView,建议使用 CALayer。 UIView 的绘制是建立在 CoreGraphic 上的,使用的是 CPU。CALayer 使用的是 Core Animation,CPU,GPU 通吃,由系统决定使用哪个。View的绘制使用的是自下向上的一层一层的绘制,然后渲染。Layer处理的是 Texure,利用 GPU 的 Texture Cache 和独立的浮点数计算单元加速 纹理 的处理。
GPU 不喜欢 透明,所以所有的绘图一定要弄成不透明,对于圆角和阴影这些的可以截个伪透明的小图然后绘制上去。在layer的回调里一定也只做绘图,不做计算!
- UITableVIew 滚动流畅性优化
影响UITableViewUITableView滚动的流畅性原因: 1. 在代理方法中做了过多的计算占用了 UI 线程的时间 2.同上 3.Cell 中 view 的组织复杂,比如使用layer并不会 ...
- UITableView滚动优化(RunLoop)
链接: 利用RunLoop优化tableView RunLoop方式优化加载tableview RunLoop总结:RunLoop的应用场景(三)滚动视图流畅性优化 TableView加载图片的优化逻 ...
- elasticsearch的数据写入流程及优化
Elasticsearch 写入流程及优化 一. 集群分片设置:ES一旦创建好索引后,就无法调整分片的设置,而在ES中,一个分片实际上对应一个lucene 索引,而lucene索引的读写会占用很多的系 ...
- UITableView 滚动时隐藏键盘
#pragma mark - UItableView滚动时收键盘 - (void)scrollViewWillBeginDragging:(UITableView *)scrollView { [se ...
- MySQL优化篇(一),我可以和面试官多聊几句吗?——SQL优化流程与优化数据库对象
我可以和面试官多聊几句吗?只是想偷点技能过来.MySQL优化篇(基于MySQL8.0测试验证),上部分:优化SQL语句.数据库对象,MyISAM表锁和InnoDB锁问题. MyISAM表锁和InnoD ...
- IOS UItableView 滚动到底 触发事件
开发过程中,在使用UItableView 总会遇到加载更多的问题,到底是手势响应瀑布流的方法好? 还是添加一个底端cell点击触发加载更多好?我也想有自己的判断.但是我们老板总说了算,没办法,谁叫我给 ...
- Spring配置表友好性优化思路
Spring配置表需要尽量保证对程序员的友好性,一下提供一种优化思路. 中途未保存,心态炸了,只贴图了,fuuuuuuuuuuuuuck 第一种(最烂,最不友好):以Json的格式保存在配置表中,程序 ...
- IO流程及优化
http://blog.csdn.net/xypzwl/article/details/51416883 一.存储设备的存储原理 机械硬盘: 机械硬盘使用磁性物质作为存储介质,用N.S极性来代表0或1 ...
- iOS - UITableView滚动到指定的cell并且选中
UITableView //项目中遇到的 - (void)selectRowAtIndexPath:(nullable NSIndexPath *)indexPath animated:(BOOL)a ...
随机推荐
- Vuex访问状态对象的方法
除了<Vuex最基本样例>中的方法外,还有两种方法访问状态对象state: 只需要改app.vue文件 方法一:引入computed <template> <div id ...
- python调用虹软2.0第二版
第一版踩了无数的坑,终于第二版把坑全添了,这次更新可以正常获取人脸数,角度,代码可读性更高,继续更新中 第三版已发出 https://www.cnblogs.com/wxt51/p/10125460. ...
- 前端项目,引入PingFang SC字体
在仿苹果官网"垃圾桶"时, 设计出的UI使用PingFang SC 字体,在网上查了很久,特记录.如果你有更好的方法,欢迎评论留言~ 实现原理,使用@font-face将字体下载在 ...
- APP Inventor 基于网络微服务器的即时通信APP
APP Inventor 基于网络微服务器的即时通信APP 一.总结 一句话总结:(超低配版的QQ,逃~) 1.APP Inventor是什么? google 傻瓜式 编程 手机 app App In ...
- bzoj 1087 状压dp
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4130 Solved: 2390[Submit][ ...
- linux-git shell colors
git config --global color.status auto git config --global color.diff auto git config --global color. ...
- Vim代码缩进设置
前段配置VPS,无奈只能使用Vim编辑Python代码,比较头疼的没法设置自动缩进,所以搜索了相关的配置,特记录如下. 将以下的设置加入到~/etc/vim/.vimrc中: set sw=4 set ...
- settings.xml配置文件详解
简单值 一半顶层settings元素是简单值,它们表示的一系列值可以配置Maven的核心行为:settings.xml中的简单顶层元素 < settings xmlns="http:/ ...
- Java环境搭建---(基础)
首先下载eclipse开发工具,下载地址:http://www.eclipse.org/downloads/,界面如下: 选择eclipse juno(4.2)的版本进入界面 点击Downloads, ...
- 网络编程之socketserver初识
网络编程之socketserver初识 Server #!/usr/bin/env python # @Author : "Wjl" # @Date : 2017/12/22 # ...