UITableView的優(yōu)化小結(jié)
UITableView在ios的實(shí)際開(kāi)發(fā)中使用頻次有多重不用多說(shuō)家卖,而它的優(yōu)化技巧既是難點(diǎn)也是必須掌握的要點(diǎn)眨层;作為一個(gè)在UITableView的優(yōu)化路上還沒(méi)走多遠(yuǎn)的初學(xué)者,最近在網(wǎng)上到處找了蠻多相關(guān)資料來(lái)閱讀上荡,自己也結(jié)合自己的項(xiàng)目做了一些思索和實(shí)踐趴樱,讓我們一起來(lái)學(xué)習(xí)吧!如果你在這方面已經(jīng)有了一些心得酪捡,鄭重推薦一個(gè)開(kāi)源項(xiàng)目VVeboTableViewDemo,值得學(xué)習(xí)叁征!
UITableView的核心簡(jiǎn)介
- UITableView的核心思想就是對(duì)UITableViewCell的重用,大概原理就是:UITableView剛開(kāi)始只會(huì)創(chuàng)建一個(gè)屏幕或者一個(gè)屏幕多一點(diǎn)的UITableViewCell逛薇,當(dāng)UITableView滑動(dòng)的時(shí)候捺疼,滑出屏幕的UITableViewCell會(huì)被放到重用池中等待重用,而由于滑動(dòng)將在屏幕上出現(xiàn)新的UITableViewCell金刁,這些UITableViewCell首先是去重用池中取帅涂,取不到再去創(chuàng)建新的;這樣做的好處就是尤蛮,你的UITableView從始至終都只會(huì)創(chuàng)建一個(gè)屏幕的UITableViewCell,而不會(huì)由于你的tableview有幾百行cell就去創(chuàng)建幾百個(gè)cell斯议。
- 要對(duì)UITableView進(jìn)行優(yōu)化产捞,主要的代碼將放在以下兩個(gè)UITableView的代理方法中:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
那么在實(shí)際開(kāi)發(fā)中,在我們創(chuàng)建好UITableView后哼御,首先多次調(diào)用heightForRowAtIndexPath的方法從而確定UITableView的contentSize和cell的位置坯临,然后調(diào)用cellForRowAtIndexPath創(chuàng)建cell焊唬,并顯示在屏幕上;優(yōu)化的部分就集中在以上兩個(gè)方法中看靠。
1.0 原始代碼
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
BTNewsFlashCell *cell = [tableView dequeueReusableCellWithIdentifier:@"NEWSCELL" forIndexPath:indexPath];
BTNewsFlashModel *model = _dataArray[indexPath.row];
cell.model = model;
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
BTNewsFlashModel *model = _dataArray[indexPath.row];
NSInteger height = model.APicHeight;
return height*WIDTH/model.APicWidth;
}
在這段代碼中第一個(gè)方法起到為cell賦值(model)的作用赶促,第二個(gè)方法起到根據(jù)數(shù)據(jù)源動(dòng)態(tài)計(jì)算行高的方法。問(wèn)題就處在第二個(gè)方法中挟炬,如果我們要?jiǎng)?chuàng)建100個(gè)cell甚至更多鸥滨,就會(huì)去計(jì)算100次,而且每當(dāng)你滾動(dòng)cell的時(shí)候還會(huì)去計(jì)算谤祖,這就很耗費(fèi)資源婿滓,甚至如果你的cell排布很復(fù)雜,那計(jì)算量就很可怕了粥喜。凸主。。oh额湘,怎么破????
1.1 優(yōu)化
我們?cè)趶木W(wǎng)上獲取到數(shù)據(jù)后卿吐,就立馬根據(jù)數(shù)據(jù)計(jì)算cell的高度,并為model添加cellHeight的屬性(保存cell的高度)锋华,在heightForRowAtIndexPath的方法中直接取來(lái)用就好了,不用每次去計(jì)算了嗡官。。哈哈 這樣會(huì)不會(huì)流暢一點(diǎn)呢供置,事實(shí)證明是的????谨湘,代碼如下
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
BTNewsFlashModel *model = _dataArray[indexPath.row];
return model.cellHeight;
}
在這里,強(qiáng)烈推薦一個(gè)好用的第三方UITableView+FDTemplateLayoutCell,只需一句代碼芥丧,完美紧阔、perfect、100分
#import "UITableView+FDTemplateLayoutCell.h"
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [tableView fd_heightForCellWithIdentifier:@"reuse identifer" configuration:^(id cell) {
// Configure this cell with data, same as what you've done in "-tableView:cellForRowAtIndexPath:"
// Like:
// cell.entity = self.feedEntities[indexPath.row];
}];
}
優(yōu)化 1.2
根據(jù)蘋果的描述续担,UIKit是我們最容易也是最常接觸到的框架擅耽,而我們使用
add subView
添加控件都由UIKit完成,但是UIKit本質(zhì)上依賴于Core Graphics框架物遇,也是基于Core Graphics框架實(shí)現(xiàn)的乖仇。所以如果想要完成某些更底層的功能或者追求極致的性能,那么推薦使用Core Graphics完成询兴。如下一部分代碼:(完整代碼見(jiàn)VVeboTableViewDemo)
- (void)draw{
if (drawed) {
return;
}
NSInteger flag = drawColorFlag;
drawed = YES;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CGRect rect = [_data[@"frame"] CGRectValue];
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor colorWithRed:250/255.0 green:250/255.0 blue:250/255.0 alpha:1] set];
CGContextFillRect(context, rect);
if ([_data valueForKey:@"subData"]) {
[[UIColor colorWithRed:243/255.0 green:243/255.0 blue:243/255.0 alpha:1] set];
CGRect subFrame = [_data[@"subData"][@"frame"] CGRectValue];
CGContextFillRect(context, subFrame);
[[UIColor colorWithRed:200/255.0 green:200/255.0 blue:200/255.0 alpha:1] set];
CGContextFillRect(context, CGRectMake(0, subFrame.origin.y, rect.size.width, .5));
}
UIImage *temp = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(), ^{
if (flag==drawColorFlag) {
postBGView.frame = rect;
postBGView.image = nil;
postBGView.image = temp;
}
});
});
[self drawText];
[self loadThumb];
}
優(yōu)化1.3
//按需加載 - 如果目標(biāo)行與當(dāng)前行相差超過(guò)指定行數(shù)乃沙,只在目標(biāo)滾動(dòng)范圍的前后指定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+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];
}
}
記得在tableView:cellForRowAtIndexPath:方法中加入判斷:
(如果cell不在加載的范圍內(nèi)诗舰,就清除掉cell上面的子控件)
if (needLoadArr.count>0&&[needLoadArr indexOfObject:indexPath]==NSNotFound) {
[cell clear];
return;
}
滾動(dòng)速度比較快的時(shí)候警儒,只加載一定范圍內(nèi)的cell,不會(huì)一次性加載太多,按需加載蜀铲,可以有效提高流暢度边琉。
總之,優(yōu)化tableView的流暢度就從三個(gè)方面著手
- 單獨(dú)計(jì)算cell的高度记劝,并保存下來(lái)
- 自己使用核心繪圖Core Graphics繪制cell上面的子視圖
- 按需加載cell
- 另外單獨(dú)推薦一篇文章【iOS開(kāi)發(fā)25種常見(jiàn)的APP性能優(yōu)化方法】变姨,里面也有一些關(guān)于tableView的優(yōu)化相關(guān)的,這里就不一一敘述了厌丑;希望我的小結(jié)對(duì)讀者有一些幫助????定欧。