谈起UITableView大家都不会陌生,因为这个视图太重要了,基本上每个App都离不开它的身影,其实它算是一个比较复杂的视图了,每个UITableView都有一个tableViewHeaderView, 我们能在tableHeaderView上面显示一些比较重要且特别的东西,比如轮播图。一个tableview包含一个到多个section,一个section又包含
一个header,一个footer和cells组成。这样复杂的视图结构,处理和渲染起来一定会给内存造成很大的压力,如果我们在开发的时候不对它做一些单独的处理,滑
动起来的时候就很可能赞成卡顿的现象,尤其是在cell里面有图片的情况。针对页面卡顿的情况,个人觉得可以从以下几个方面进行优化:
1、重用机制
2、懒加载
3、尽量不要使用不透明视图
4、善用drawRect(减少视图数目)
5、缓存cell高度
6、滑动不加载
前四种方式比较简单,这里就不在做过多的赘述,只是需要注意cell被重用时,它内部绘制的内容并不会被自动清除,因此你可能需要调用setNeedsDisplayInRect:或setNeedsDisplay方法。
这里主要介绍以下cell高度的缓存和滑动不加载两种方式:
缓存cell高度主要是利用到了策略模式,将计算cell高度的代码单独抽离出来,其中cell缓存高度的代码如下:
首先我们需要建一个模型类,用来接收缓存的cell高度,下面是模型的.h文件:
ViewController中的代码如下:
#import "ViewController.h"
#import "HeightModel.h"
@interface ViewController ()<UITableViewDelegate, UITableViewDataSource>{
NSMutableArray *_data;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_data = [NSMutableArray array];
NSString *string = @"李白(701年2月8日—762年12月)[1] ,字太白,号青莲居士,又号“谪仙人”,汉族,绵州昌隆县(今四川省江油市)人,是唐代伟大的浪漫主义诗人,被后人誉为“诗仙”。与杜甫并称为“李杜”,为了与另两位诗人李商隐与杜牧即“小李杜”区别,杜甫与李白又合称“大李杜”。其人爽朗大方,爱饮酒作诗,喜交友。";
for (int i = 0; i < 20; i++) {
//造假数据
NSInteger num = arc4random() % string.length;
NSString *subString = [string substringToIndex:num];
//开始计算文字高度
CGFloat height = [self labelAutoSizeWithText:subString Font:14 MaxSize:CGSizeMake(300, 10000)].height;
HeightModel *model = [HeightModel new];
model.text = subString;
model.cellHeight = [NSString stringWithFormat:@"%f",height];
[_data addObject:model];
}
}
//返回size的方法
- (CGSize)labelAutoSizeWithText:(NSString *)text Font:(NSInteger)font MaxSize:(CGSize)maxSize {
NSDictionary *dic = @{
NSFontAttributeName:[UIFont systemFontOfSize:font]
};
return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading | NSStringDrawingTruncatesLastVisibleLine attributes:dic context:nil].size;
}
#pragma mark -- UItableViewDelegate UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _data.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
HeightModel *model = _data[indexPath.row];
return [model.cellHeight floatValue] + 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 300, 0)];
[label setNumberOfLines:0];
[label setTag:123];
[label setFont:[UIFont systemFontOfSize:14]];
[cell.contentView addSubview:label];
}
HeightModel *model = _data[indexPath.row];
//找到label
UILabel *label = (UILabel *)[cell.contentView viewWithTag:123];
//修改label 的frame
[label setFrame:CGRectMake(10, 10, 300, [model.cellHeight floatValue])];
//为label赋值
label.text = model.text;
label.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 256.0 green:arc4random() % 255 / 256.0 blue:arc4random() % 255 / 256.0 alpha:1];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
以上就是cell高度缓存的方法,下面我们再来介绍以下滑动不加载的方法:
首先我们要创建一个模型,模型的.h文件如下
然后我们再创建一个cell,创建cell我用的时xib的方法,cell中的代码如下:
在cell的.h文件提供对模型赋值的方法,这样做可以减少controller的压力,尤其是tableView:cellForRowAtIndexPath这个代理方法的压力,
cell的.m文件如下
tableViewController的.m中代码如下:
#import "ViewController.h"
#import "ImageCell.h"
#import "ImageModel.h"
#define kImageUrl @"http://h.hiphotos.baidu.com/image/h%3D300/sign=0e698f82d643ad4bb92e40c0b2025a89/03087bf40ad162d92589103b16dfa9ec8a13cdb6.jpg"
@interface ViewController ()<UITableViewDelegate, UITableViewDataSource> {
NSMutableArray *_data;
}
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_data = [NSMutableArray array];
NSArray *array = @[@{@"picUrl":kImageUrl},@{@"picUrl":kImageUrl},
@{@"picUrl":kImageUrl},@{@"picUrl":kImageUrl},
@{@"picUrl":kImageUrl},@{@"picUrl":kImageUrl},
@{@"picUrl":kImageUrl},@{@"picUrl":kImageUrl}
];
for (NSDictionary *dic in array) {
ImageModel *model = [[ImageModel alloc] init];
[model setValuesForKeysWithDictionary:dic];
model.isLoad = NO;
[_data addObject:model];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self loadShowCells];
});
}
//加载可见cell 请求数据
- (void)loadShowCells {
NSArray *array = [self.tableView indexPathsForVisibleRows];
for (NSIndexPath *indexPath in array) {
//1、获取cell
ImageCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
ImageModel *model = _data[indexPath.row];
[cell setImageWithModel:model];
}
}
#pragma mark UIScrollViewDelegate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self loadShowCells];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (!decelerate) {
[self loadShowCells];
}
}
#pragma mark UITableViewDelegate UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _data.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = @"ImageCell";
ImageCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[NSBundle mainBundle] loadNibNamed:@"ImageCell" owner:self options:nil].lastObject;
}
ImageModel *model = _data[indexPath.row];
if (model.isLoad) {
//此时执行的这个方法是在缓存中提取
[cell setImageWithModel:model];
} else {
//显示占位图
[cell setImageWithModel:nil];
}
//对cell进行赋值
// ImageModel *model = _data[indexPath.row];
// [cell setImageWithModel:model];
return cell;
}
这样就做好了UITableView的全部优化,做到了上面六点,你的tableView应该很流畅了吧!