在IOS开发中,UITableView是最重要,最常用的控件之一。而对于UITableView的优化,也是IOS开发程序员必须要思考的问题。刚好前段时间,做的一个项目就碰到有关UITableView优化,自己也找了很多资料,所以在这里整理一下我对tableView优化的理解。
1.cell的重用
UITableView中最重要的就是cell的重用机制,只要是用了UITableView控件,就必定会涉及cell的重用。cell的重用机制:当tableView显示的时候,只会创建在可视范围的cell,为了使这些cell可以重用,cell在创建的时候会有一个重用标识 ReuseIdentifier。当屏幕滚动时,有部分cell就会被移出屏幕,这些cell会被放到一个缓存池中,等待重用。当需要显示一个cell的时候,首先会到缓存池中查看有没有对应的可重用的cell,如果有,就直接拿来用,如果没有,再去创建,这样就会大大减少内存的消耗。
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: ReuseIdentifier)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(ReuseIdentifier, forIndexPath: indexPath)
return cell
}
2.缓存行高
在呈现cell之前,把cell的高度计算好缓存起来,避免每次加载cell的时候都要计算。对于高度的计算,还有个小细节需要注意,就是如果 row 的高度都一定,那就删除代理中的这个 tableView:heightForRowAtIndexPath: 方法,设置 Table View 的 rowHeight 属性。
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
//获得模型
let model = models![indexPath.row]
//判断模型里面之前有没有缓存过行高
if model.rowHeight != nil {
return model.rowHeight!
}
//自己算行高:AutoLayout
//让 cell自己对应内容,直接获取高度,这个cell不参与显示
let cell = tableView.dequeueReusableCellWithIdentifier(ReuseIdentifier) as! CJStatusCell
cell.model = model
let heigth = cell.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
//保存行高
model.rowHeight = heigth
return heigth
}
3.cellForRowAtIndexPath不要做耗时操作
主线程主要是用来显示UI,刷新界面的,为了不影响界面的流畅程度,耗时的操作都放到子线程去执行。
4.尽量不要去添加和移除view, 先将会用到的控件懒加载,要就显示,不要就隐藏。如果cell中有图片控件,就使用异步加载图片。
5.减少cell上subviews的数量
UITableViewCell包含了textLabel、detailTextLabel和imageView等,而你还可以自定义一些视图放在它的contentView里。然而view是很大的对象,创建它会消耗较多资源,并且也影响渲染的性能。
6.cell里面的控件,约束最好不要使用remake,动态添加约束是比较耗性能的
7.cell里面的控件,背景最好是不透明的 (图层混合), view的背景颜色 clearColor尽量少
8.图片圆角不要使用 layer.cornerRadius,图层最好不要使用阴影, 阴影会导致离屏渲染
9.异步绘制
我在这边写了一个UIImage的分类,是用来异步绘制。
import UIKit
extension UIImage {
func cj_AsyncDrawImage(var size: CGSize?, bgColor: UIColor? = UIColor.whiteColor(), isCorner: Bool = false, drawFinish: (image: UIImage)->()) {
let start = CACurrentMediaTime()
if size == nil {
//别人没有传入size
size = self.size
}
//上下文大小为rect
let rect = CGRect(origin: CGPointZero, size: size!)
//开启上下文
UIGraphicsBeginImageContextWithOptions(size!, bgColor != nil, UIScreen.mainScreen().scale)
//设置背景颜色
bgColor?.setFill()
UIRectFill(rect)
//需要圆角
if isCorner {
//路径
let path = UIBezierPath(ovalInRect: rect)
//让后面绘制的元素在路径里面
path.addClip()
}
self.drawInRect(rect)
//获取图片
let newImage = UIGraphicsGetImageFromCurrentImageContext()
//结束上下文
UIGraphicsEndImageContext()
let end = CACurrentMediaTime()
// CJPrint("异步绘制时间:\(end - start)")
//返回绘制好的图片
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
drawFinish(image: newImage)
}
}
}