最近在微博上看到一个很好的开源项目,是关于如何优化UITableView的,加上正好最近也在优化项目中的相似朋友圈功能这块,思考了不少关于UITableView的优化技巧,因此决定详细的整理下对优化UITableView的理解,须要的朋友们能够参考借鉴。面试
1、介绍缓存
iOS开发中,UITableView多是平时咱们打交道最多的UI控件之一,其重要性不言而喻。Android也是如此,Android中的ListView和UITableView是相同功能的一个控件,可是iOS的UITableView更为强大一点,缘由就不说了,若是你学过Android就知道iOS中的UITableView使用起来是很是简单的,这也是峰哥喜欢iOS赛过Android的缘由之一。今天研究的内容就是UITableView的优化。性能优化
开始以前,你能说出几种UITableView的可优化项?cell复用(Android中常常称为ListView的重用,其实重用复用都是一个意思,因为峰哥以前作过Android的缘由,有时候我常常说“重用”,后面万一说“重用”你们知道是“复用”的意思就好了)!除了cell重用呢?多线程
2、UITableView的性能优化异步
一、cell复用ide
复用很简单,这或许是全部iOS开发者最为熟知的一个优化内容,以下代码:布局
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *Identifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
return cell;
}性能
可是,这样重用就完美了吗?学习
咱们常常在注意cellForRowAtIndexPath:中为每个cell绑定数据,实际上在调用cellForRowAtIndexPath:的时候cell尚未被显示出来,为了提升效率咱们应该把数据绑定的操做放在cell显示出来后再执行,能够在tableView:willDisplayCell:forRowAtIndexPath:(之后简称willDisplayCell)方法中绑定数据。优化
注意willDisplayCell在cell 在tableview展现以前就会调用,此时cell实例已经生成,因此不能更改cell的结构,只能是改动cell上的UI的一些属性(例如label的内容等)。
二、cell高度的计算
这边咱们分为两种cell,一种是定高的cell,另一种是动态高度的cell。
(1)定高的cell,应该采用以下方式:
self.tableView.rowHeight = 88;
这个方法指定了全部cell高度都是88的tableview,rowHeight默认的值是44,因此一个空的TableView会显示成这个样子。对于定高cell,直接采用上面方式给定高度,不须要实现tableView:heightForRowAtIndexPath:以节省没必要要的计算和开销。
(2)动态高度的cell
咱们须要实现它的代理,来给出高度:
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// return xxx
}
这个代理方法实现后,上面的rowHeight的设置将会变成无效。在这个方法中,咱们须要提升cell高度的计算效率,来节省时间。
自从iOS8以后有了self-sizing cell的概念,cell能够本身算出高度,使用self-sizing cell须要知足如下三个条件:
(1)使用Autolayout进行UI布局约束(要求cell.contentView的四条边都与内部元素有约束关系)。
(2)指定TableView的estimatedRowHeight属性的默认值。
(3)指定TableView的rowHeight属性为UITableViewAutomaticDimension。
(void)viewDidload {
self.myTableView.estimatedRowHeight = 44.0;
self.myTableView.rowHeight = UITableViewAutomaticDimension;
}
除了提升cell高度的计算效率以外,对于已经计算出的高度,咱们须要进行缓存,对于已经计算过的高度,没有必要进行计算第二次。
做为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个个人iOS交流群:519832104 无论你是小白仍是大牛欢迎入驻,分享经验,讨论技术,你们一块儿交流学习成长!
另附上一份各好友收集的大厂面试题,须要iOS开发学习资料、面试真题,能够添加iOS开发进阶交流群,进群可自行下载!
三、渲染
为了保证TableView的流畅,当快速滑动的时候,cell必须被快速的渲染出来。因此cell渲染的速度必须快。如何提升cell的渲染速度呢?
(1)当有图像时,预渲染图像,在bitmap context先将其画一遍,导出成UIImage对象,而后再绘制到屏幕,这会大大提升渲染速度。具体内容能够自行查找“利用预渲染加速显示iOS图像”相关资料。
(2)渲染最好时的操做之一就是混合(blending)了,因此咱们不要使用透明背景,将cell的opaque值设为Yes,背景色不要使用clearColor,尽可能不要使用阴影渐变等
(3)因为混合操做是使用GPU来执行,咱们能够用CPU来渲染,这样混合操做就再也不执行。能够在UIView的drawRect方法中自定义绘制。
四、减小视图的数目
咱们在cell上添加系统控件的时候,实际上系统都会调用底层的接口进行绘制,大量添加控件时,会消耗很大的资源而且也会影响渲染的性能。当使用默认的UITableViewCell而且在它的ContentView上面添加控件时会至关消耗性能。因此目前最佳的方法仍是继承UITableViewCell,并重写drawRect方法。
五、减小多余的绘制操做
在实现drawRect方法的时候,它的参数rect就是咱们须要绘制的区域,在rect范围以外的区域咱们不须要进行绘制,不然会消耗至关大的资源。
六、不要给cell动态添加subView
在初始化cell的时候就将全部须要展现的添加完毕,而后根据须要来设置hide属性显示和隐藏。
七、异步化UI,不要阻塞主线程
咱们时常会看到这样一个现象,就是加载时整个页面卡住不动,怎么点都没用,仿佛死机了通常。缘由是主线程被阻塞了。因此对于网路数据的请求或者图片的加载,咱们能够开启多线程,将耗时操做放到子线程中进行,异步化操做。这个或许每一个iOS开发者都知道的知识,没必要多讲。
八、滑动时按需加载对应的内容
若是目标行与当前行相差超过指定行数,只在目标滚动范围的先后指定3行加载。
(void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
NSIndexPath *ip = [self indexPathForRowAtPoint:CGPointMake(0, targetContentOffset->y)];
NSIndexPath *cip = [[self indexPathsForVisibleRows] firstObject];
NSInteger skipCount = 8;
if (labs(cip.row-ip.row)>skipCount) {
NSArray *temp = [self indexPathsForRowsInRect:CGRectMake(0, targetContentOffset->y, self.width, self.height)];
NSMutableArray *arr = [NSMutableArray arrayWithArray:temp];
if (velocity.y<0) {
NSIndexPath *indexPath = [temp lastObject];
if (indexPath.row+33) {
[arr addObject:[NSIndexPath indexPathForRow:indexPath.row-3 inSection:0]];
[arr addObject:[NSIndexPath indexPathForRow:indexPath.row-2 inSection:0]];
[arr addObject:[NSIndexPath indexPathForRow:indexPath.row-1 inSection:0]];
}
}
[needLoadArr addObjectsFromArray:arr];
}
}
记得在tableView:cellForRowAtIndexPath:方法中加入判断:
if (needLoadArr.count>0&&[needLoadArr indexOfObject:indexPath]==NSNotFound) {
[cell clear];
return;
}
滑动很快时,只加载目标范围内的cell,这样按需加载(配合SDWebImage),极大提升流畅度。
总结
以上就是这篇文章的所有内容了,但愿本文的内容对你们的学习或者工做能带来必定的帮助,若是有疑问你们能够留言交流。
点击此处,当即与iOS大牛交流学习