此文整理一下 TableView 优化相关的方案和思路。
TableView 为什么会卡?
主要由以下原因:
cellForRowAtIndexPath:
方法中处理了过多业务- tableviewCell 的 subview 层级太复杂,做了大量透明处理
- cell 的 height 动态变化时计算方式不对
优化核心思想: UITableViewCell
重用机制
简单的理解就是:UITableView 只会创建一屏幕(或一屏幕多一点)的 UITableViewCell,其他都是从中取出来重用的。每当 Cell 滑出屏幕时,就会放入到一个集合(或数组)中(这里就相当于一个重用池),当要显示某一位置的 Cell 时,会先去集合(或数组)中取,如果有,就直接拿来显示;如果没有,才会创建。这样做的好处可想而知,极大的减少了内存的开销。
Tips:
- 提前计算并缓存好高度(布局),因为
heightForRowAtIndexPath:
是调用最频繁的方法; - 异步绘制,遇到复杂界面,参考
Facebook
的AsyncDisplayKit
和YYAsyncLayer异步绘制框架; - 缓存图片(
SDWebImage
),提前处理好UIImageView
图片的尺寸按需加载而不是加载原图; - 计算等耗时操作异步处理,处理完再回主线程更新 UI;
- 图文混排不定高度采用
CoreText
排版,缓存 Cell 高度参考YYKit; - 实现 Cell 的
drawRect:
方法直接绘制,减少UIView
,UIImageView
,UILabel
等容器的使用。
Bonus:
- 正确使用 reuseIdentifier 来重用 Cell;
- 尽量少用或不用透明图层或 View;
- 如果 Cell 内现实的内容来自 web,使用异步加载,缓存请求结果;
- 减少 subviews 的数量在
heightForRowAtIndexPath:
中尽量不使用cellForRowAtIndexPath:
,如果你需要用到它,只用一次然后缓存结果; - 尽量少用 addView 给 Cell 动态添加 View,可以初始化时就添加,然后通过 hide 来控制是否显示;
- 固定高度不要实现
heightForRowAtIndexPath:
方法。
可以通过实现以下方法,可以减少高度计算次数
1 | @property (nonatomic) CGFloat rowHeight; // will return the default value if unset |
参考资料: