若是问iOS中最重要的最经常使用的UI控件是什么,我以为UITableView当之无愧!彷佛全部常规APP都使用到了UITableView。下面就讲一讲UITableView的经常使用知识和使用原理及性能优化!css
UITableView继承于UIScrollview,所以它默认支持垂直滚动(只支持垂直滚动)html
UITableView性能极佳,它能够出色的完成咱们工做中的不少功能。nginx
UITableView一共有两种样式:UITableViewStylePlain 和 UITableViewStyleGroupweb
效果分别如图:canvas
UITableViewStylePlain:一种平铺的效果,而且分组组头默认有停靠效果;缓存
UITableViewStyleGroup:一种组间分离的效果,每组之间间距较明显,有明显分组迹象。ruby
说完了UITableView的简介,下面来讲说他它是如何展现数据的。性能优化
UITableView和数据源的关系以下markdown
数据源方法的调用过程app
调用以下方法,查询一共有多少组数据
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented
调用以下方法,查询每一组一共有多少行数据
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
调用以下方法,查询每一行显示什么样的内容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
UITableView还有一些其余的数据源方法以下
/** * 返回组头标题 */ - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; /** * 返回尾标题 */ - (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section; ···
最简单的返回UITableViewCell的方法以下
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [[UITableViewCell alloc] init]; cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row]; return cell; }
可是实际使用过程当中这样是很是耗费性能的,由于当用户滑动UITableView的时候,上面方法会疯狂的调用,疯狂的建立UITableViewCell。
苹果对这种状况作了一些性能优化,UITableViewCell在每次建立的时候只会建立当前UI页面上可见的Cell。当Cell滑动到屏幕外面,当前Cell会被放入到缓存池中,而且能够给Cell设置一个复用标识,当下次使用Cell的时候能够先到缓存池中查找,若是有对应复用标识的Cell就直接拿出来使用,并从新给内容赋值。
因此根据苹果复用Cell的思路咱们在调用返回cell的方法思路应该以下:
因此上面方法从提升性能角度考虑,应该从新写为下面这样:
/** * 何时调用:每当有一个cell进入视野范围的时候调用 */ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 0.建立cell复用标识 static NSString *reuseIdentifier = @"cell"; // 1.根据复用标识在复用池中进行查找 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; // 2.判断若是复用池cell为nil就根据复用标识本身建立 if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; } // 3.拿到cell进行数据覆盖 cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row]; return cell; }
咱们能够手动给tableview注册对应标识的cell,保证从缓存池中能加载到对应标识的cell。
经过代码注册
// 注册cell static NSString *reuseIdentifier = @"cell"; [tableview registerClass:[UITableViewCell class] forCellReuseIdentifier:reuseIdentifier];
经过Xib注册
// 注册cell static NSString *reuseIdentifier = @"cell"; // 标识能够在Xib中建立 [tableview registerNib:[UINib nibWithNibName:@"对应的Xib名称" bundle:nil] forCellReuseIdentifier:reuseIdentifier];
在数据源方法中返回cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 1.根据复用标识在复用池中进行查找 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; // 2.拿到cell进行数据覆盖 cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row]; return cell; }
第三种方式是经过UITableViewController在StoryBoard中建立,见下面:5.UITableViewController
有了数据源方法,tableview就能够正常展现数据。有了对应的代理方法就能够正常监听tableview的事件操做。
下面列举一些经常使用代理方法:
/** 返回行高,可根据不一样行返回不一样高 @param tableView tableview @param indexPath 位置 @return 行高 */ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; /** 返回估计行高,此方法不进行真实计算,课改变Cell计算高度方法的调用顺序, @param tableView tableview @param indexPath 位置 @return 行高 */ - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath; /** cell的点击事件处理 @param tableView tableview @param indexPath 位置 */ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; /** cell将要被选中 -- 先需取消选中某个cell才能正常选中新的cell */ - (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath; /** cell将要被取消选中 */ - (nullable NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath ···
UITableViewController继承自UIViewController。能够方便建立有tableview的控制器
在StoryBoard中建立UITableViewController并加载cell步骤以下:
设置Dynamic Prototypes动态类型的内容,下面数量至少为1
设置cell的复用标识identfier
在代码中直接加载对应cell便可(无需判空/建立)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 1.会默认去缓存池中进行查找,若是没有自动去StoryBaord中找 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; // 2.拿到cell进行数据覆盖 cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row]; return cell; }
经过StoryBoard建立Cell更加方便
小结