本文下面就略微总结一下UITableView性能优化那些事.,普京网址:本文下面就略微总结一下UITableView性能优化那点事.

iOS_UITableView性能优化那点事,ios_uitableview

UITableView在实际开发中使用频率实在是很高, 因此,
UITableView的性能优化是必不可少的,
本文下面就略微总结一下UITableView性能优化那点事.

 

本文着重介绍具体方法, 原理的话在文章最后会给出一些链接,
有兴趣可以自行查看.

 

  1. 关于数据绑定

很多新加入iOS的朋友喜欢把数据绑定写入在UITableView Data Source方法 

– (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath

里面. 这并不是十分之准确的, 因为这时候的cell还没有被实际产生,
试着把数据绑定写在 

– (void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath
*)indexPath;

这个方法上, 因为这时候cell已经被创建而且正在准备显示到界面上了.

 

  1. 关于cell的重用.

cell的重用是苹果官方就一再推荐的,
所以保证自己创建的cell是重用的会对性能提升有很大的帮助.

 

  1. 关于高度计算

高度计算的方法如果调用多次, 对性能损耗是肯定的.
当然如果你的高度是定死的话, 就不会出现这个问题. 如果不是的话,
那么你可能需要自己设计一个方法, 把每个需要显示的cell的高度先计算出来,
然后再设置cell高度的时候直接调用.

提供一个计算cell内容高度的方法(截取网上的):

普京网址 1

然后高度设置可以在下面实现:

普京网址 2

 

  1. 关于AutoLayout

尽管苹果官方推荐使用autoLayout进行程序开发,
但是autoLayout会带来性能的一些损耗, 当然,
如果你的程序对性能要求不是很高的话, 用autoLayout进行开发也是很方便的.

 

  1. 关于CPU和GPU的调度使用

各种透明度, 圆角等layer的属性都会引起性能损耗.

所以, 可以试着不要直接设置图片的圆角, 先异步获取图片, 调用CoreGraphics
处理好图片再返回

这样你的图片处理就交给了后台而不会影响到你程序的流畅性了

 

  1. 关于其他优化方法

可以试着使用这个 框架,
框架集成了大量异步操作, 把UIView -> CALayer 转变成 CAlayer ->
Node, 这样的轻量级控件加上异步操作, 会使你的程序性能更上一层楼.

 

 

附上一些链接:

1.

2. 

 

然后推荐几个喜欢的技术博客吧:

1. 

2. 

3. 

4. 

 

最后, 最近apple pay好像挺火的. 转一篇之间的文章:

 

UITableView在实际开发中使用频率实在是很高, 因此,
UITableView的性能优化是必不可少的, 本文下面就…

UITableView在实际开发中使用频率实在是很高, 因此,
UITableView的性能优化是必不可少的,
本文下面就略微总结一下UITableView性能优化那些事.

tableView的简单认识

UITableView最核心的思想就是UITableViewCell的重用机制。简单的理解就是:重用机制实现了数据和显示的分离,并不为每个数据创建一个UITableViewCell,我们只创建屏幕可显示的最大的cell个数+1,然后去循环重复使用这些cell,既节省空间,又达到我们需要显示的效果.。这样做的好处可想而知,极大的减少了内存的开销,尽管这样但是我们在做项目的时候会发现有的时候滑动tableView还是会很卡顿

在iOS应用中,UITableView应该是使用率最高的视图之一了。iPod、时钟、日历、备忘录、Mail、天气、照片、电话、短信、Safari、App
Store、iTunes、Game
Center⋯几乎所有自带的应用中都能看到它的身影,可见它的重要性。

介绍:UITabelView是iOS开发中最常用,
也是最灵活的控件.用途最广泛.

 

剖析

我们来看看UITableView的回调方法,其中有两个非常重要的回调

  • (UITableViewCell *)tableView:(UITableView *)tableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath
  • (CGFloat)tableView:(UITableView *)tableView
    heightForRowAtIndexPath:(NSIndexPath *)indexPath
    相信这个两个回调大家都不陌生,那下面我问大家个问题,这两个回调会先调用那个呢?理想上我们是会认为UITableView会先调用前者,再调用后者,因为这和我们创建控件的思路是一样的,先创建它,再设置它的布局。但实际上却并非如此,我们都知道,UITableView是继承自UIScrollView的,需要先确定它的contentSize及每个Cell的位置,然后才会把重用的Cell放置到对应的位置。我们知道了UITableView会先走
  • (CGFloat)tableView:(UITableView *)tableView
    heightForRowAtIndexPath:(NSIndexPath *)indexPath
    回调,我们可以在这里把我们需要展示的数据尺寸算出来,那么问题来了
    怎么算。

然而在使用第三方应用时,却经常遇到性能上的问题,普遍表现在滚动时比较卡,特别是table
cell中包含图片的情况时。

两种风格:

本文着重介绍具体方法, 原理的话在文章最后会给出一些链接,
有兴趣可以自行查看.

怎么算

我们需要创建两个模型:
一个是数据模型

 @interface TableViewModel : NSObject
/**正文文字*/
@property (nonatomic, strong) NSString *text;
/**图片链接*/
@property (nonatomic, strong) NSString *photo_URL;
/**图片数组*/
@property (nonatomic, strong) NSArray *photoArr_URL; 
@end

一个Frame模型

 @interface TableViewFrameModel : NSObject
 @property (nonatomic, strong) TableViewModel *model;
  /**正文的frame*/
 @property (nonatomic, assign) CGRect contentF;
  /**图片的frame*/
 @property (nonatomic, assign) CGRect photosViewF;
  /**cell的高度*/
 @property (nonatomic, assign) CGFloat cellHeight;
 @end

我们请求到数据之后,把数据模型给Frame模型让他帮我们把数据算出

NSArray *model = [TableViewModel mj_objectArrayWithKeyValuesArray:self.items];
for (TableViewModel *infomodel in model) {
    TableViewFrameModel *frameModel = [[TableViewFrameModel alloc] init];
    frameModel.model = infomodel;
    [_infoFrameModel addObject:frameModel];
}

我们最终获得到一个Frame模型数组(_infoFrameModel),我们只需要

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
TableViewFrameModel *frame = self.infoFrameModel[indexPath.row];
return frame.cellHeight;
}

这样我们就可以先把每一行Cell的高度计算,然后去铺数据

  • (UITableViewCell *)tableView:(UITableView *)tableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    NSString *ID = @”cell”;
    AdaptiveCell *cell = [tableView
    dequeueReusableCellWithIdentifier:ID];
    if (!cell) {
    cell = [[AdaptiveCell alloc] initWithStyle:UITableViewCellStyleValue1
    reuseIdentifier:ID];
    }
    cell.frameModel = self.infoFrameModel[indexPath.row];
    return cell;
    }
    这样就大大的提高了UITableView的性能

实际上只要针对性地优化一下,这种问题就不会有了。有兴趣的可以看看LazyTableImages这个官方的例子程序,虽然也要从网上下载图片并显示,但滚动时丝毫不卡。

UITableViewStylePlain 和 UITableViewStyleGrouped。

UITableView中只有行的概念,每一行就是一个UITableViewCell。UITableViewCell内置好的控件contentView父控件

contentView = (textLabel,detailTextLabel)+
UIImage控件(imageView)分别用于容器、显示内容、详情和图片。

 

总结

  • 我们需要提前计算好每行Cell内的控件大小和每行Cell的高度
  • 异步加载:比如我们加载图片可是使用(SDWebImage)也可以提高我们tableView的性能
  • 创建控件尽量少使用addView在Cell添加控件,可以在开始的时候创建,通过hidden来设置显示和隐藏
  • 尽量少使用或者不使用透明图层和圆角设置

Demo

本人新手呆鸟,忘各位老司机多多鞭策,使我快速成长。谢啦

下面就说说我对UITableView的了解。不过由于我也是初学者,或许会说错或遗漏一些,因此仅供参考。

代理方法、数据源方法:<UITableviewDelegate,UITableviewDataSource>

  1. 关于数据绑定

首先说下UITableView的原理。有兴趣的可以看看《About Table Views in
iOS-Based Applications》。

– (NSInteger)numberOfSectionsInTableView:(UITableView )tableView     
numberOfRowsInSection:(NSInteger)section{        return 5;}

//有多少组(默认为1)

– (UITableViewCell )tableView cellForRowAtIndexPath:(  NSIndexPath
identifily = @”cellIdentifily”;      UITableViewCell )tableView
willDisplayCell:(UITableViewCell )indexPath{         
NSLog(@”willDisplayCell”);} //cell内容设置,属性设置

– (void)tableView:(UITableView )cell
forRowAtIndexPath:(NSIndexPath)tableView   
didEndDisplayingHeaderView:(UIView )tableView   
didEndDisplayingFooterView:(UIView )tableView   
heightForRowAtIndexPath:(NSIndexPath )tableView   
heightForHeaderInSection:(NSInteger)section{              return
15.0f;}  //滑动时,cell消失时调用

很多新加入iOS的朋友喜欢把数据绑定写入在UITableView Data Source方法 

UITableView是UIScrollView的子类,因此它可以自动响应滚动事件。

点击cell时调用

– (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath

它内部包含0到多个UITableViewCell对象,每个table
cell展示各自的内容。当新cell需要被显示时,就会调用tableView:cellForRowAtIndexPath:方法来获取或创建一个cell;而不可视时,它又会被释放。由此可见,同一时间其实只需要存在一屏幕的cell对象即可,不需要为每一行创建一个cell。

– (void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath )indexPath;

里面. 这并不是十分之准确的, 因为这时候的cell还没有被实际产生,
试着把数据绑定写在 

此外,UITableView还可以分为多个sections,每个区段都可以有自己的head、foot和cells。而在定位一个cell时,就需要2个字段了:在哪个section,以及在这个section的第几行。这在iOS
SDK中是用NSIndexPath来表述的,UIKit为其添加了indexPathForRow:inSection:这个创建方法。

离开点击时调用

– (void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath
*)indexPath;

其他诸如编辑之类的就不提了,因为和本文无关。

– (void)deselectRowAtIndexPath:(NSIndexPath *)indexPath
animated:(BOOL)animated;

这个方法上, 因为这时候cell已经被创建而且正在准备显示到界面上了.

介绍完原理,接下来就开始优化吧。

重用机制->滚筒原理->只有固定->屏的视图超出后重用这一屏的视图一直滚动循环使用只需更改上面的数据
 DataSource有两个必须实现的代理方法没有实现就会出现警告——>运行崩溃

 

使用不透明视图。

Required:

  1. 关于cell的重用.

不透明的视图可以极大地提高渲染的速度。因此如非必要,可以将table
cell及其子视图的opaque属性设为YES。

– (NSInteger)tableView:(UITableView*)tableView
numberOfRowsInSection:(NSInteger)section;//行数

– (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath;//cell展示内容

– (CGFloat)tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section;设置表头的高度

– (CGFloat)tableView:(UITableView *)tableView
heightForFooterInSection:(NSInteger)section;//设置表尾的高度

– (nullable UIView *)tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger)section;//设置表头的视图

– (nullable UIView *)tableView:(UITableView *)tableView
viewForFooterInSection:(NSInteger)section;//设置表尾的视图

– (nullable NSString *)tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section;//设置表头的标题

– (nullable NSString *)tableView:(UITableView *)tableView
titleForFooterInSection:(NSInteger)section;//设置表尾的标题

– (nullable NSString *)tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section{return
@”首页”;}//设置表头的标题

– (CGFloat)tableView:(UITableView*)tableView
heightForFooterInSection:(NSInteger)section{return100;}//设置表尾的高度

//每个分组上边预留的空白高度

-(CGFloat)tableView:(UITableView*)tableView
heightForHeaderInSection:(NSInteger)section

{return20;}

cell的重用是苹果官方就一再推荐的,
所以保证自己创建的cell是重用的会对性能提升有很大的帮助.

其中的特例包括背景色,它的alpha值应该为1(例如不要使用clearColor);图像的alpha值也应该为1,或者在画图时设为不透明。

刷新数据

 

当一个view是透明的,iOS需要渲染一个像素两次或多次,这是因为一个像素同时属于很多subviews。这是一个非常耗时的过程。

刷新整个TableVIew[self.tableView reloadData];

  1. 关于高度计算

通过代码或者InterfaceBuilder能够很简单的做到。开发者应该多次检查所有的subviews是不透明的。

1.刷新一个cell、

高度计算的方法如果调用多次, 对性能损耗是肯定的.
当然如果你的高度是定死的话, 就不会出现这个问题. 如果不是的话,
那么你可能需要自己设计一个方法, 把每个需要显示的cell的高度先计算出来,
然后再设置cell高度的时候直接调用.

对于自定义代码,你可以通过代码来设置,如下:

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0
inSection:0];[self.tableViewreloadRowsAtIndexPaths:[NSArray
arrayWithObjects:indexPath,nil]withRowAnimation:UITableViewRowAnimationFade];

提供一个计算cell内容高度的方法(截取网上的):

view.opaque = YES;

2.刷新一个section

普京网址 1

不要重复创建不必要的table cell。

NSIndexSet *indexSet = [[NSIndexSet alloc]
initWithIndex:0];[self.tableView
reloadSections:indexSetwithRowAnimation:UITableViewRowAnimationFade];

然后高度设置可以在下面实现:

前面说了,UITableView只需要一屏幕的UITableViewCell对象即可。因此在cell不可见时,可以将其缓存起来,而在需要时继续使用它即可。

转载:

普京网址 2

而UITableView也提供了这种机制,只需要简单地设置一个identifier即可:

iOS
tableview那些事

 

static NSString *CellIdentifier = @”xxx”;

  1. 关于AutoLayout

UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];

尽管苹果官方推荐使用autoLayout进行程序开发,
但是autoLayout会带来性能的一些损耗, 当然,
如果你的程序对性能要求不是很高的话, 用autoLayout进行开发也是很方便的.

if (cell == nil) {

 

cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];

  1. 关于CPU和GPU的调度使用

}

各种透明度, 圆角等layer的属性都会引起性能损耗.

值得一提的是,cell被重用时,它内部绘制的内容并不会被自动清除,因此你可能需要调用setNeedsDisplayInRect:或setNeedsDisplay方法。

所以, 可以试着不要直接设置图片的圆角, 先异步获取图片, 调用CoreGraphics
处理好图片再返回

此外,在添加table
cell的时候,如果不需要动画效果,最好不要使用insertRowsAtIndexPaths:withRowAnimation:方法,而是直接调用reloadData方法。因为前者会对所有indexPaths调用tableView:cellForRowAtIndexPath:方法,即便该cell并不需要显示(不知道是不是bug),这就可能创建大量多余的cell。勘误:只是在模拟器上测试如此,真机调试时没有这种bug。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章