学计算机的那个

不是我觉到、悟到,你给不了我,给了也拿不住;只有我觉到、悟到,才有可能做到,能做到的才是我的.

0%

UITableView优化

UITableView是iOS开发中的常用控件,用来加载列表数据,当数据量大或者布局过于复杂的时候有可能出现卡顿,影响用户体验。

缓存高度

UITableView 的 UITableViewDelegate 里面有个方法 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; 专门用于获取 Cell 的高度 。由于UITableView在绘制 Cell 的时候每次会主动获取 Cell 的高度,所以这里的优化点是减少该方法的执行时间。保存第一次计算出来的 Cell 高度,并保存到 Cell 对应的 Model 上 ,而不是每次重复计算 Cell 的高度,可以达到减少该方法的执行时间的目的。

异步渲染UITableViewCell

如果一个UITableViewCell使用系统自带的View进行布局的层级很多时,可以考虑对TableViewCell进行优化,减少View的层级,也就是对TableViewCell异步渲染。

按需加载UITableViewCell

判断按需加载的 indexPaths , 如果目标行与当前行相差超过指定行数,只在目标滚动范围的前后指定3行加载。这样可以减少 UITableView 的绘制工作量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- (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];
// velocity.y<0 下拉, velocity.y>0 上拉
if (velocity.y<0) {
NSIndexPath *indexPath = [temp lastObject];
if (indexPath.row+3<datas.count) {
[arr addObject:[NSIndexPath indexPathForRow:indexPath.row+1 inSection:0]];
[arr addObject:[NSIndexPath indexPathForRow:indexPath.row+2 inSection:0]];
[arr addObject:[NSIndexPath indexPathForRow:indexPath.row+3 inSection:0]];
}
} else {
NSIndexPath *indexPath = [temp firstObject];
if (indexPath.row>3) {
[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];
}
}

当 UITableView 开始绘制 Cell 的时候,若是 indexpath 包含在按需绘制的 needLoadArr 数组里面,那么就异步绘制该 Cell ,如果没有则跳过该 Cell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
VVeboTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell==nil) {
cell = [[VVeboTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:@"cell"];
}
// 绘制 Cell
[self drawCell:cell withIndexPath:indexPath];
return cell;
}

// 按需绘制 Cell
- (void)drawCell:(VVeboTableViewCell *)cell withIndexPath:(NSIndexPath *)indexPath{
NSDictionary *data = [datas objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell clear];
cell.data = data;
// 按需绘制,只要在 needLoadArr 里面的 indexPath 才需要绘制 Cell
if (needLoadArr.count>0&&[needLoadArr indexOfObject:indexPath]==NSNotFound) {
[cell clear];
return;
}
if (scrollToToping) {
return;
}
[cell draw];
}

参考

1.UITableView 的优化技巧

2. Code