UITableView 优化整理

下面根据这些优化策略来使用代码展示


UITableView滑动优化.png

1: 尽量少的Cell的类型

当Cell的结构基本差不多时候,可以将Cell只创建一种Cell,这样Cell的体积会增大,但是Cell的数量不会有很多,

UITableViewCell的复用机制是离屏就会进入缓存池中,那么一屏可以有N个Cell,那个一种Cell的缓存数就是N+1,如果有M种Cell,那么缓存数就是M*N个.利用同一种类型的cell,去灵活利用view的hidden属性,可以很好的降低Cell的类型数量,不过依照实际需求看.

typedefenum: NSUInteger {   
FriendsterCellTypeNone = -1,//错误码  不存在
FriendsterCellTypeAll  =0,//default
FriendsterCellTypeImage,   
FriendsterCellContent,} FriendsterCellType;

@interfaceFriendsterTableViewCell:UITableViewCell

@property(nonatomic,strong)FriendsterModel *model;//不设置照片 这个先可以不看,后面优化会用到
@property(nonatomic,strong)FriendsterModel *noImageModel;

@end

2: 提前计算Cell的高度

系统会先调用“tableView:heightForRowAtIndexPath:”获取每个Cell即将显示的高度,从而确定整个UITableView的布局。然后才调用“tableView:cellForRowAtIndexPath”获取每个Cell,我们也是在这里填充、设置Cell的。

在Model中计算并保存Cell的高度

@interfaceFriendsterModel:NSObject

@property(nonatomic,strong)NSString*icon_url;

@property(nonatomic,assign)CGRecticonF;

@property(nonatomic,strong)UIImage*iconImage;

@property(nonatomic,strong)NSString*content;

@property(nonatomic,assign)CGRectcontentF;

@property(nonatomic,strong)NSString*name;

@property(nonatomic,assign)CGRectnameF;

@property(nonatomic,strong)NSString*img_url;

@property(nonatomic,assign)CGRectimgF;

@property(nonatomic,assign)CGFloatcellHeight;

@property(nonatomic,assign)FriendsterCellType cellType;

@property(nonatomic,assign)BOOLisAnimation;

+ (instancetype)friendsterWithDict:(NSDictionary*)dict;

- (instancetype)initWithDict:(NSDictionary*)dict;

//这个方法是返回对应Cell的高度的,可以在数据层计算好每一个Cell的高度,之后直接从缓存中取出来就可以了,因为UITableView的调用之前会先把所有的Cell的高度全部获取一遍,这里就是返回高度的地方,如果在这里大量计算,会延迟TableView的加载

- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{   

FriendsterModel *model =self.dataArray[indexPath.row];

return model.cellHeight;

}

3: 缓存展示数据
例子: 内容页有类似于富文本形式的展示类的东西,
可以将富文本在数据层处理好,缓存在数据中,展示的时候直接复制即可,不用在创建NSMutableAttributedString 来组装数据

4: 缓存展示Cell

对于一些简单的,小的View,可以缓存在数据层,用的时候直接拿出来,不用在Cell里面进行重复创建.

5: 对于不透明的View,设置opaque为YES,这样在绘制该View时,就不需要考虑被View覆盖的其他内容(尽量设置Cell的view为opaque,避免GPU对Cell下面的内容也进行绘制).

6: 尽量减少 Cell 的视图层级,可以使用异步绘制的方式,并且少用或不用透明的视图。尽量显示“大小刚好合适的图片资源”

7: 避免离屏渲染,比如同时使用

view.layer.masksToBounds= YES;
view.layer.cornerRadius=20.0;

可以用 使用CAShapeLayer和UIBezierPath设置圆角.

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100,100,100,100)];
imageView.image= [UIImage imageNamed:@"3"];
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.boundsbyRoundingCorners:UIRectCornerAllCorners cornerRadii:imageView.bounds.size];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];//设置大小
maskLayer.frame= imageView.bounds;//设置图形样子
maskLayer.path= maskPath.CGPath;
imageView.layer.mask= maskLayer;
[self.viewaddSubview:imageView];

8: 快速滑动时按需加载

快滑动过程中,只加载目标范围内的Cell,这样按需加载,极大的提高流畅度。

- (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:[NSIndexPathindexPathForRow: indexPath.row-3 inSection: 0]];

                            [arr addObject:[NSIndexPathindexPathForRow: indexPath.row-2 inSection: 0]];

                                [arr addObject:[NSIndexPathindexPathForRow: indexPath.row-1 inSection: 0]];
                   }       
         }       
        [needLoadArr addObjectsFromArray:arr];   
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    ...
        if(needLoadArr.count>0 && [needLoadArr indexOfObject:indexPath] == NSNotFound) { 
              [cell clear];
             return; 
      }
    ...
}

9: 图片加载优化:

当用户手动 drag table view 的时候,会加载 cell 中的图片; * 在用户快速滑动的减速过程中,不加载过程中 cell

中的图片(但文字信息还是会被加载,只是减少减速过程中的网络开销和图片加载的开销);

在减速结束后,加载所有可见 cell 的图片(如果需要的话);

/*

优化达到的效果

1: 当用户手动 drag table view 的时候,会加载 cell 中的图片;

2: 在用户快速滑动的减速过程中,不加载过程中 cell 中的图片(但文字信息还是会被加载,只是减少减速过程中的网络开销和图片加载的开销);

3: 在减速结束后,加载所有可见 cell 的图片(如果需要的话);

4: 在减速结束后,需要显示的Cell的图片要优先下载.

scrollViewWillBeginDragging 即将开始拖拽

scrollViewWillEndDragging: withVelocity: targetContentOffset: 即将停止拖拽

scrollViewDidEndDecelerating 已经停止减速

进一步优化

1: 如果内存中有图片的缓存,减速过程中也会加载该图片

2: 如果图片属于 targetContentOffset 能看到的 cell,正常加载,这样一来,快速滚动的最后一屏出来的的过程中,用户就能看到目标区域的图片逐渐加载

*/

//即将开始拖动

- (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView{

       NSLog(@"%s",__func__);//   

      _isNeedLoadImage = NO;

}

//即将停止拖动  滚动很快时,只加载目标范围内的Cell,这样按需加载,极大的提高流畅度。

- (void)scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint*)targetContentOffset{

      NSLog(@"%s",__func__);

      //  先获取当前开始减速时第几行

      NSIndexPath*ip = [self.tableView indexPathForRowAtPoint:CGPointMake(0, targetContentOffset->y)];

      NSIndexPath*cip = [[self.tableView indexPathsForVisibleRows] firstObject];

      NSLog(@"%@",ip);

      NSLog(@"%@",cip);

      NSIntegerskipCount =6;//判断快速滑动的cell跨越的数量

      if(labs(cip.row-ip.row)>skipCount) { 

            _isQuickScroll =YES;   

             }else{

          _isQuickScroll =NO;   

      }
}

//即将开始减速- (void)scrollViewWillBeginDecelerating:(UIScrollView*)scrollView{

      NSLog(@"%s",__func__); 

      _isDecelerationing =YES;

}

//已经停止减速

- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView{

NSLog(@"%s",__func__);

      _isNeedLoadImage =YES;

      _isDecelerationing =NO;

      _isQuickScroll =NO;

    //刷新当前屏幕可见CEll

    [self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
}

完成!!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,825评论 4 377
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,887评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,425评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,801评论 0 224
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,252评论 3 299
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,089评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,216评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 31,005评论 0 215
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,747评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,883评论 2 255
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,354评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,694评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,406评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,222评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,242评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,017评论 2 281

推荐阅读更多精彩内容