标签(空格分隔): UITableView UITableViewCell UITableView性能优化 UITableView性能优化精讲面试
参考文章编程
摘要:UITableView是iOS开发中很是重要的控件之一,它可以展现多行数据,支持滚动.在大部分APP中都占有很大的比重.那么有关UITableView的性能优化也显得尤其重要,本文后面也将着重讲这个。数组
##UITableView的简单使用 ###一、UITableView的建立缓存
代码方式性能优化
//tableView的建立必须制定一个样式,样式在初始化以后不能修改
//tableView分两种风格,Plain:不分区,grouped:分区
_tableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
//告诉tableView,它上面的cell是根据UItableViewCell建立的,若是重用的cell找不到,系统会根据这个类来建立一个cell,不须要编程人员建立
//解释2://给tableView的某个重用标示符注册一个类,当tableView找这个重用标示符的cell,若是找不到,就会自动建立这个类的对象,(始终能找到可重用的cell)
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
[self.view addSubview:_tableView];
复制代码
xib方式 在设计界面拖入,并在属性检查器中设置各类属性bash
###二、UITableView的属性网络
// 设置每一行cell的高度
self.tableView.rowHeight = 80;
// 设置每一组的头部标题高度
self.tableView.sectionHeaderHeight = 50;
// 设置每一组的尾部标题高度
self.tableView.sectionFooterHeight = 50;
// 设置分割线的颜色
self.tableView.separatorColor = [UIColor redColor];
// 设置分割线的样式
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
// 设置表头控件---这里主要应用是打广告
self.tableView.tableHeaderView = [[UISwitch alloc] init];
// 设置表尾控件---这里主要应用是加载数据
self.tableView.tableFooterView = [[UISwitch alloc] init];
// 设置索引条的文字颜色
self.tableView.sectionIndexColor = [UIColor orangeColor];
// 设置索引条的背景颜色
self.tableView.sectionIndexBackgroundColor = [UIColor yellowColor];
复制代码
###三、隐藏TableView分割线的方法app
// 方法一:设置分割线的颜色
self.tableView.separatorColor = [UIColor clearColor];
// 方法二:设置分割线的样式
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
复制代码
###四、UITableViewCell的属性布局
//cell中默认包含的空间
cell.imageView
cell.textLabel
cell.detaliTextLabel
cell.contentView
// 设置右边显示的指示控件
// accessoryView的优先级 > accessoryType
cell.accessoryView = [[UISwitch alloc] init];
// 设置右边显示的指示样式
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// 设置cell选中的样式
// 设置cell的选中样式无
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// 下面三种方式在iOS7以后,表现形式同样了,都是灰色
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.selectionStyle = UITableViewCellSelectionStyleDefault;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
复制代码
###五、设置cell的背景颜色性能
// 整体效果为大背景蓝色,字体背景为红色,下面代码能够调换顺序,效果同样
cell.backgroundColor = [UIColor redColor];
UIView *bg = [[UIView alloc] init];
bg.backgroundColor = [UIColor blueColor];
cell.backgroundView = bg;
复制代码
###六、设置cell选中的背景View
// 设置cell选中的背景view
UIView *seletedBg = [[UIView alloc] init];
seletedBg.backgroundColor = [UIColor yellowColor];
cell.selectedBackgroundView = seletedBg;
复制代码
###七、两个协议
tablewView代理方法的执行顺序。 UITableView返回多少组----->每组返回多少行cell--->计算每一个cell的高度---->指定cell布局
UITableViewDelegate
/**
* 1.当用户点击(选中)某一行cell就会调用这个方法
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"选中了:%zd",indexPath.row);
}
/**
* 2.当用户取消点击(选中)某一行cell就会调用这个方法
*/
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"取消选中了:%zd",indexPath.row);
}
/**
* 3.返回每一组的头部高度
*/
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
}
/**
* 4.返回每一组的尾部高度
*/
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
}
/**
* 5.返回每一行cell的高度
*/
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row % 2 == 0) {
return 50;
} else {
return 100;
}
}
/**
* 6.返回每一组的头部控件
*/
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
return [UIButton buttonWithType:UIButtonTypeContactAdd];
}
/**
* 7.返回每一组的尾部控件
*/
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return [UIButton buttonWithType:UIButtonTypeContactAdd];
}
/*
* 8.设置每一行的编辑样式:当表处于编辑状态时,默认的编辑样式为删除
*/
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
//编辑状态为删除
return UITableViewCellEditingStyleDelete;
//编辑状态为插入
//return UITableViewCellEditingStyleInsert;
}
//经过edditing的值来显示编辑状态
_tableView.editing = !_tableView.editing;
/*
* 9.表提交编辑状态的时候会调用这个方法
*/
-(void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[_dataArray removeObjectAtIndex:indexPath.row];
[_tableView reloadData];
}
/*
* 10.设置编辑中删除的文字
*/
-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
return @"走你";
}
/*
* 11.右侧按钮被点击时会调用该方法
*/
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"调用了cell右侧按钮的方法");
}
复制代码
###八、两个协议二:UITableViewDataSources
/**
* 告诉tableView一共有多少组数据
*/
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
/**
* 告诉tableView第section组有多少行
*/
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
/**
* 告诉tableView每一行显示的内容(tableView每一行的内容是是第一个UITableViewCell)
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
/**
* 告诉tableView每一组的头部标题
*/
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
/**
* 告诉tableView每一组的尾部标题
*/
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
/**
* 返回索引条的文字
*/
- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
// NSMutableArray *titles = [NSMutableArray array];
// for (XMGCarGroup *group in self.carGoups) {
// [titles addObject:group.title];
// }
// return titles;
// 抽取self.carGoups这个数组中每个元素(XMGCarGroup对象)的title属性的值,放在一个新的数组中返回
return [self.carGoups valueForKeyPath:@"title"];
复制代码
##2、UITableViewCell 在UITableView中,每个单元格被称为cell,若是想在UITableView中显示数据,须要设置UITableView中cell的数量及每一个cell显示的内容.UITableView并不能直接显示数据,它须要设置数据源(datasource),数据源遵照协议,并实现其中对应的方法设置数据及内容便可. ###UITableViewCell的建立
设置Cell的三个属性
cell.imageView //cell左边的图片
cell.textLabel
cell.detailTextLabel
复制代码
经过自定义类 建立一个累继承于UITableViewCell,添加以下属性
@property (nonatomic,retain)UIImageView *headerImageView;
@property (nonatomic,retain)UILabel *nameLabel;
@property (nonatomic,retain)UILabel *timeLabel;
@property (nonatomic,retain)UILabel *messageLabel;
@property (nonatomic,retain)UIImageView *picImageView;
复制代码
.m文件中的实现
//若是是alloc建立的cell,各个自定义属性空间的初始化代码写在init方法中
(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//头像
_headerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(8, 8, 60, 60)];
_headerImageView.layer.cornerRadius = 30;
_headerImageView.layer.masksToBounds = YES;
[self.contentView addSubview:_headerImageView];
//名字
_nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(76, 8, 240, 20)];
_nameLabel.font = [UIFont boldSystemFontOfSize:16];
_nameLabel.textColor = [UIColor redColor];
[self.contentView addSubview:_nameLabel];
//发布时间
_timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(76, 36, 240, 20)];
_timeLabel.font = [UIFont systemFontOfSize:12];
[self.contentView addSubview:_timeLabel];
//动态正文
_messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, 76, 304, 60)];
_messageLabel.font = [UIFont systemFontOfSize:16];
//numberOfLines行数,设置为0不限制行数。
_messageLabel.numberOfLines = 0;
[self.contentView addSubview:_messageLabel];
//动态配图
_picImageView = [[UIImageView alloc] initWithFrame:CGRectMake(8, 144, 100,100)];
[self.contentView addSubview:_picImageView];
}
return self;
}
复制代码
经过xib自定义 首先建立一个带xib的UITableViewCell,拖控件设置cell高度。拉线生成属性;
自定义类中
//若是cell是从xib中加载的,那么不走init方法,因此初始化代码不能写在init方法中
//当自身从xib中加载的时候调用,因此自定义xib的代码应该在这里实现
(void)awakeFromNib {
[super awakeFromNib];
// Initialization code
_headerImageView.layer.cornerRadius = 30;
_headerImageView.layer.masksToBounds = YES;
}
复制代码
注册重用
```
//给TableView的某个重用标示符注册一个xib,当tableView找这个标识符时,若是找不 到,就会自动从注册的西边中区加载一个cell。
[_tableView registerNib:[UINib nibWithNibName:@"CustomCell" bundle:nil] forCellReuseIdentifier:@"cell"];
```
复制代码
##3、性能优化
1)尽可能使用cell的复用。
使用cell的复用,能够减小内存的开销,没有开辟新的空间,也减小了一些计算量。
复用原理:当滚动列表时(UITableView)部分cell会移除Window 可是移除的cell并无被当即释放 而是放到了一个叫作复用池的对象池中,处于待定状态,当有新的cell要出如今Window界面上时,首先会从复用池中寻找是否有相同类型的cell,若是有直接拿过用(最直观的表现是新出现的cell有没有开辟新的内存空间),若是没有,建立一个新的类型的cell,因此UITableView可能拥有多种类型的cell,复用池也可能存储着多种类型的cell,系统经过定义reuseIndentifer做为每一个cell的惟一标示符来肯定即将出现的cell复用何种类型的cell。
2)对于不定高的cell 提早将每一个cell的高度存入数组,出现一个cell的时候,直接从数组中拿出确切的高度便可,不用临时计算cell的高度。对于固定高的cell和不定高的cell一样适用。一样也能够在存储在model中,在获取数据后要赋值给model时进行计算。
3)涉及网络请求加载数据在UITableView滑动结束的时候在进行加载数据(渲染)避免卡顿。
一、UITableView继承自UIScrollView,继承了后者的方法。
//滑动结束的方法
- (void)scrollViewDidEndDragging:(UIScrollView*)scrollView willDecelerate:(BOOL)decelerate
//减速结束以后的方法
- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView
二、在tableView必须实现的二个方法中(加载cell的方法中)将数据的渲染写在如下if语句中
if(self.tableView.dragging==NO&&self.tableView.decelerating==NO)
复制代码
4)对于tableView的自定义控件 尤为是UIImageView,尽可能减小使用圆角,阴影等layer属性,尽可能减小使用alpha(透明度)来设置透明度,(在项目开发中,让UI设计师设计原图就是带圆角的图) 阴影,圆角这些layer效果都是在GPU中完成的。
一、当多个视图重叠时,一个像素同时属于不少subviews,GPU会进行合成渲染,须要渲染一个像素两次或屡次,而渲染的最慢的操做就是混合。所以当视图结构太过复杂,就会大量消耗GPU的资源。因此当一个空间自己是不透明,注意设定alpha为1,这样能够避免无用的alpha通道合成,下降GPU的负载。 另外在layer层渲染图层时会涉及上下文切换以及离屏渲染之类的,系统开销会很大,特别是在cell视图很复杂的时候,因为渲染问题致使的内存开销会让你的tableview很是卡顿。好比cell中须要设置头像圆形直接设置圆角会很卡,那么咱们能够用Quartz2d把拿到的图片处理一遍在给cell使用。
二、对控件设置cornerRadius后对其进行clip或mask操做时 会致使offscreenrendering这个也是在GPU中进行的 若是在滑动时 圆角对象太多 回到GPU的负载大增幅。
这时咱们能够设置layer的shouldRasterize属性为YES,能够将负载转移给CPU,更完全的是直接使用带圆角的原图。
5)尽可能使用懒加载
懒加载又称为延迟加载,其实是重写某个对象的getter方法 原理:程序一开始并不对它进行初始化 而是在用到他的时候 才为他开辟内存供它使用。
好处:
一、没必要将建立的对象的代码所有写在ViewDidLoad中,代码可读性强。 二、每一个控件的getter方法,分别负责各自的实例化处理,代码彼此之间独立性强 松耦合。
6)减小返回给的cell里面的处理逻辑和处理时间。
以驴妈妈为例:各个UI控件整合到一块儿,实际上只有一个控件。
7)设置每一个cell的opaque属性 ----面试亮点
opaque意思是不透明的 浑浊的 有YES和NO二个结果,若是控件自己不透明,咱们设置opaque为YES。
opaque为YES表示告诉iOS当前视图背后没有须要绘制的内容,同时容许iOS的绘图方法经过一些优化来加速当前视图的绘制。
为何咱们设置Alpha的值为1的时候仍然要设置opaque的属性为YES? Alpha属性只对当前须要绘制的视图起做用,若是当前视图并无填满父视图或者当前视图上存在一些洞(由Alpha通道所致),那么图像视图下方的内容将仍然可见,无论Alpha的值是多少。选中就是让iOS明白不须要为图像视图以后的东西浪费绘制时间。
如下是官方描述
default is YES. opaque views must fill their entire bounds or the results are undefined. the active CGContext in drawRect: will not have been cleared and may have non-zeroed pixels
8)分段加载数据
设置分页加载数据,也就是上拉刷新和下拉加载。
如下是cell简单复用代码
#import "ViewController.h"
#import "XMGTestCell.h"
@interface ViewController ()
@end
@implementation ViewController
NSString *ID = @"wine";
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.rowHeight = 100;
// 注册 ID这个标识 对应的 cell类型 为UITableViewCell这种类型
[self.tableView registerClass:[XMGTestCell class] forCellReuseIdentifier:ID];
}
#pragma mark - 数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 200;
}
/**
* 每当一个cell进入视野范围内就会调用1次
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.去缓存池取可循环利用的cell
XMGTestCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 2.设置数据
cell.textLabel.text = [NSString stringWithFormat:@"第%zd行数据",indexPath.row];
return cell;
}
复制代码