UITableView滚动性能优化

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

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

2、Cell里的图片吃GPU(在tableView:cellForRowAtIndexPath:中

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 那个方法里了,在这里尽可能的少计算,但是却忽略了另一个很轻松就能提升加载时间的方法(尽可能的让 height For Row At Index Path这个方法的计算复杂度为 O(1)) :

1 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
2     //  Table View 在每次 reload data 时都会要所有 cell 的高度!这就是说你有一百行 cell,就像代理要100次每个cell 的高度,而不是当前屏幕显示的cell 的数量的高度!
3     //  结论:
4     //  1、对于cell的高度不一定一样的:应该把cell的高度缓存起来。将计算行高的时间提前到,从服务器搂回数据的时候,初始化model的时候就马上计算行高,再缓存起来。例如可以缓存到FrameModel里
5     //  2、对于cell的高度都一样的:不要重载这个代理方法,直接在初始化tableView的地方赋值给rowHeight属性,同理,各分区头或各分区尾高度一样的话,应用sectionFooterHeight和sectionHeaderHeight,而不用代理方法。
6    //   3、如果只是刷新某row就可以解决问题的话,尽量用reloadRowsAtIndexPaths:withRowAnimation\reloadSections:withRowAnimation,而非用reloadData 另外同理,尽量用insertRowsAtIndexPaths:withRowAnimation:deleteRowsAtIndexPaths:withRowAnimation:等,代替reloadData。
7 }

tableView:cellForRowAtIndexPath:

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

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

优化建议:

1、与后台和UI的同事沟通,在iOS端显示的要是尺寸小的缩略图,而非原图。

2、缩略图要不透明的png。(如果背景不是单一颜色的话,那就只好是透明背景的png,但这毕竟是极端少数的情况)

3、把cell以及cell里面的view(例如UIImageView)设置为不透明,把opaque的值设置YES(xib就是把勾勾上)

4、如果与后台和UI同事沟通无果,从网络搂回来图片都是很大的话,先根据需要显示的图片大小切成合适大小的图。

另外,有一种情况,后台不能返回圆角的,cell的图片需要做圆角,要自己画的。通常我们先会想到类似下面的方法:

1 view.layer.cornerRadius = 5;
2 view.layer.maskToBounds = YES;

如果你的圆角视图不多,cell 不复杂,的确用上面两句就好。但实际工作中,多数是大量的cell,则性能的损耗是非常大的。

优化建议:

1、如果能够只用 cornerRadius 解决问题,就不用优化。

2、如果必须设置 masksToBounds ,可以参考圆角视图的数量,如果数量较少(一页只有几个)也可以考虑不用优化。

3、UIImageView 的圆角通过直接截取图片实现,其它视图的圆角可以通过 Core Graphics 画出圆角矩形实现。

 1 extension UIImage {
 2     func kt_drawRectWithRoundedCorner(radius radius: CGFloat, _ sizetoFit: CGSize) -> UIImage {
 3         let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: sizetoFit)
 4
 5         UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.mainScreen().scale)
 6         CGContextAddPath(UIGraphicsGetCurrentContext(),
 7             UIBezierPath(roundedRect: rect, byRoundingCorners: UIRectCorner.AllCorners,
 8                 cornerRadii: CGSize(width: radius, height: radius)).CGPath)
 9         CGContextClip(UIGraphicsGetCurrentContext())
10
11         self.drawInRect(rect)
12         CGContextDrawPath(UIGraphicsGetCurrentContext(), .FillStroke)
13         let output = UIGraphicsGetImageFromCurrentImageContext();
14         UIGraphicsEndImageContext();
15
16         return output
17     }
18 }
 1 extension UIImageView {
 2     /**
 3      / !!!只有当 imageView 不为nil 时,调用此方法才有效果
 4
 5      :param: radius 圆角半径
 6      */
 7     override func kt_addCorner(radius radius: CGFloat) {
 8         self.image = self.image?.kt_drawRectWithRoundedCorner(radius: radius, self.bounds.size)
 9     }
10 }
时间: 2024-10-05 04:01:28

UITableView滚动性能优化的相关文章

优化UITableView滚动性能

自定义的cell如下: 第一个:Instruments测试,iphone4 38fps-45fps,iphone3G 25fps // table with normal XIB based cells - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"CustomC

【UIKit】UITableView.05 性能优化

UITableView.05 性能优化: [为何要性能优化]:TableView拖屏过程中,不断有对象"消失"在屏幕上,但是这样的对象还是存在的,当拖拉过多后,导致内存严重泄漏. 解决方法:仅提供有限的对象,拖拉过程中,只是将内存地址存放的内容进行改变. [旧代码] -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITable

UITableView的性能优化1

UITableView作为ios中使用最频繁的控件之一,其性能优化也是常常要面对的,尤其是当数据量偏大并且设备性能不足时.本文旨在总结tableview的几个性能优化tips,并且随着认识的深入,本文将持续更新,力求将tableview的优化做到极致! Let`s begin! 治病就要先知道病因,我们先来分析一下影响tableview滚动性能的因素有哪些: 1 2 3 1.cellForRowAtIndexPath方法中处理了过多业务 2.tableviewCell的subview层级太复杂,

UITableView的性能优化

UITableView作为ios中使用最频繁的控件之一,其性能优化也是常常要面对的,尤其是当数据量偏大并且设备性能不足时.本文旨在总结tableview的几个性能优化tips,并且随着认识的深入,本文将持续更新,力求将tableview的优化做到极致! Let`s begin! 治病就要先知道病因,我们先来分析一下影响tableview滚动性能的因素有哪些: 1 2 3 1.cellForRowAtIndexPath方法中处理了过多业务 2.tableviewCell的subview层级太复杂,

关于UITableView的性能优化(历上最全面的优化分析)

(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 这个代理方法的实现,在可见的页面是会重复绘制页面的,所以绝大部分人都会在这里做一些代码处理 比如: static NSString *CellIdentifier = @"LazyTableCell"; UITableViewCell *cell = [tableView dequeue

页面滚动性能优化之passive

passive有何用? 正如标题所言,passive就是为了让浏览器的页面滚动起来更加丝滑,飞一般的感觉~ ? passive怎么用 看完还是不懂,不着急,看下述慢慢道来 ? passive的前世今生 对于addEventListener(),大家都是认识的,为dom添加触发事件,那么,今天的故事就从这里开始. 在早期addEventListener是这样的: addEventListener(type, listener, useCapture) 其中useCapture:是否允许事件捕捉,但

UITableView简单性能优化

iOS设备的内存有限,如果用UITableView显示成千上万条数据,就需要成千上万个UITableViewCell对象的话,那将会耗尽iOS设备的内存.要解决该问题,需要重用UITableViewCell对象 重用原理:当滚动列表时,部分UITableViewCell会移出窗口,UITableView会将窗口外的UITableViewCell放入一个对象池中,等待重用.当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个对象池,

【IOS开发】UITableView的性能优化

一..重用cell 在数据源方法中,在可见的页面重复绘制 OC方法中 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; SWIFT方法 override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITabl

UITableView的性能优化10个小技巧

通常你会发现一个图片类的app会在一个imageView上做下面这些事情: 1  下载图片(主要的内容图片+用户头像图片)2  更新时间戳3  展示评论4  计算动态的cell的高度 Tip#1 学习怎么提升速度 1.打开你的项目并点击Product>Profile 2.在那儿选择Custom 3.找到添加按钮并且添加工具:Allocations,Time,Profile,Leaks 4.观察你的应用,以及他的表现. Tip#2 避免阻塞主线程 在这个例子中你会看到第一个图片相关的方法在数据下载