ios基础之UITableViewCell的重用(带示例原创)
之前一个月刚刚系统的开始接触IOS开发,对UI控件大体了解了一遍,但是因为没有实际的参与项目,对细枝末节的还是不很清楚。
昨天突然想到:UITableViewCell的重用到底是怎么回事,上网查了许多资料后略有体会,但大都差不多,于是想自己实验一下。
便新建了个single view的工程,在storyboard上拖了个tableview,用最基础的方法绑定了cell,并用了重用。
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//为表格行定义一个静态字符串作为标示
static NSString *cellID = @"cellId";
NSLog(@"hanghao:%ld",(long)indexPath.row);
//从可重用的表格行的队列中取出一个表格行
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
NSLog(@"重新创建对象");
switch (indexPath.row % ) {
case :
//使用UITableViewCell创建普通单元格,使用自定义的LYCTableViewCell创建自定义单元格
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
break;
case :
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
break;
case :
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellID];
break;
case :
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:cellID];
break;
default:
break;
}
}
//单元格设为圆角
cell.layer.cornerRadius = ;
cell.layer.masksToBounds = YES; //获取当前的行号
NSUInteger rowNo = indexPath.row;
cell.textLabel.text = [books objectAtIndex:rowNo];
//为uitableviewcell左端设置图片
cell.imageView.image = [UIImage imageNamed:@"123.png"];
//设置左端高亮图片
cell.imageView.highlightedImage = [UIImage imageNamed:@"123_h.png"]; cell.detailTextLabel.text = [details objectAtIndex:rowNo];
return cell;
}
说实话,刚开始接触的时候真不知道 dequeueReusableCellWithIdentifier 这是个什么东西,后来在网上搜索的时候说这是根据id查找可重用的cell,但是说的太笼统了,到底什么算是可重用cell?
如果这个table中有多个自定义类型的cell,该怎么重用,这个问题纠结了一下午,到晚上睡觉前终于想通了。
先说简单的情况,当我们的tableview种的cell为单一类型,而且cell的高度是一个统一的高度,即显示一个这样的列表:

例如上图,那么在 -(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
方法中,if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cID];
    }
这几行代码将被执行11次,也就是创建11个指向不同地址的cell。
为什么是11次?因为当前window中显示了11个cell,虽然最后一个只显示了一半。(如果在iphone 6 plus中,创建的cell肯定大于11个,因为屏幕比5s的大)
这是在静止时候创建的cell。
那么当我们滑动屏幕的时候,有会发生或者触发哪些操作呢?

上面的图中,为将tableview向上滑动了一点,出现了一个新的cell(android高级),这个时候,系统会在创建一个新的cell对象,此时的内存中会有12个cell的对象。
当我们继续向上滑动,当[C#高级编程]对应的那个cell消失在tableview的可视区域的时候,那个cell将被tableview放到他的重用列表中。
而新出现的cell将会重用重用列表中的那个cell,只是对cell中的文本重新赋值而已,
这样一直循环:当用户滚动tableview时,如果cell不可见,将被扔进可重用列表,在其他行即将显示在tableview中时,重用那个cell,重新复制,以达到节省内存的效果。
按照上面的例子,那么内存中最多会创建12个cell,即使你的datasource中有1000条数据,也还是12个cell对象在内存中,只是tableview替我们控制了显示隐藏时重用cell。
如果我们不在编程时使用重用机制,那么可想而知,创建1000个甚至10000个cell在内存中,是多么浪费。
上面讲了单一种类cell的现实,那么多种cell是怎么显示的呢,其实只要上面的思路清晰了,那么多种cell也是同样的道理。
先上一下源代码
 #pragma mark - Table view data source
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
     // Return the number of sections.
     return ;
 }
 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     // Return the number of rows in the section.
     NSLog(@"rowNumber");
     if (section %  == ) {
         return ;
     }
     return ;
 }
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     static NSString *defaultCellID = @"default";
     static NSString *firstCellID = @"first";
     //注册可重用cell
     if (!_isRegistNib) {
         NSLog(@"registernib");
         UINib *nib = [UINib nibWithNibName:@"CustomTableCellDefaultView" bundle:nil];
         [tableView registerNib:nib forCellReuseIdentifier:defaultCellID];
         UINib *nibFirst = [UINib nibWithNibName:@"HomeTableCellFirstView" bundle:nil];
         [tableView registerNib:nibFirst forCellReuseIdentifier:firstCellID];
         _isRegistNib = !_isRegistNib;
     }
     NSInteger sectionIndex = indexPath.section;
     if (sectionIndex %  == ) {
         //如果是第一个区域,显示欢迎的cell
         HomeTableCellFirst *cell = (HomeTableCellFirst *)[tableView dequeueReusableCellWithIdentifier:firstCellID forIndexPath:indexPath];
         NSLog(@"创建第一个cell");
         NSLog(@"cell的地址是:%@",cell);
         NSLog(@"--------------------------------------");
         return cell;
     }
     else if(sectionIndex %  == ){
         //如果是第二个区域,显示普通的cell
         CustomTableCellDefault *cell = (CustomTableCellDefault *)[tableView dequeueReusableCellWithIdentifier:defaultCellID forIndexPath:indexPath];
         NSLog(@"创建普通的cell");
         NSLog(@"cell的地址是:%@",cell);
         NSLog(@"--------------------------------------");
         cell.lblStoreName.text = [NSString stringWithFormat:@"店家%ld",(indexPath.row+)];
         return cell;
     }
     else{return nil;}
 }
 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 {
     if (indexPath.section %  == ) {
         return ;
     }
     return ;
 }
 -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
 {
     return ;
 }
上面的tableview实在ib中拖进去的,style时group
在代码中设置了section的数量是4,在- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
方法中,使用registerNib:forCellReuseIdentifier方法注册了两种自定义的cell,并且会打印cell的地址及其他信息,先来看下运行效果

刚打开view的时候,tableview一共加载了[cell1]一个,[cell2] 7个。
当我们继续向上滚动的时候,因为当前[cell2]的数量并不能充满整个window,所以还会继续创建cell2的对象,与此同时,唯一的一个cell1消失在window的时候,被tableview扔进了重用列表。

通过上面的图,看到nslog打印出来的cell指向的地址,很清楚,我们创建了7个不同的[cell2]对象
当继续滚动的时候,会继续打印出和上面地址不重复的[cell2],大家可以自己试试,我就不上图了
因为我让第三个section又显示了[cell1],所以继续向下滚动,当它出现时,控制台打印的cell的地址是0x7fbc2176c620,和第一个cell是同一个对象,因为使用了重用列表中的那个[cell1]的对象。
通过上面的实验,可以总结下面的结论:
使用重用机制后:
1、tableview至少会创建可视区域高度 / cell高度 个 cell对象,因为当第一个cell隐藏了一半时,意味着要还要创建一个新的cell
2、创建了足够多的cell后,再显示cell就会使用可重用队列中的cell
以上是本人自己的理解,如果不对的地方,还希望和大家多多交流。
ios基础之UITableViewCell的重用(带示例原创)的更多相关文章
- 【ios开发】UITableViewCell的重用
		
移动开发需要解决的一个问题就是资源稀缺的问题.多数情况下是内存问题. 虽然现在的手机都号称大内存,高配置.但是移动app所占用的资源也在跟着不断膨胀, 也是造成内存不足的主要原因. 在前面的例子中,还 ...
 - iOS基础篇(十三)——UITableView(一)重用机制
		
UITableView是app开发中常用到的控件,功能很强大,常用于数据的显示.在学习UITableView使用之前,我们先简单了解一下: 1.UITableView的重用机制 UITableView ...
 - iOS面试必备-iOS基础知识
		
近期为准备找工作面试,在网络上搜集了这些题,以备面试之用. 插一条广告:本人求职,2016级应届毕业生,有开发经验.可独立开发,低薪求职.QQ:895193543 1.简述OC中内存管理机制. 答:内 ...
 - iOS基础 - UITableView的数据源(dataSource)和代理(delegate)
		
UITableView的数据源(dataSource)和代理(delegate) UITableView需要一个数据源(dataSource)来显示数据,UITableView会向数据源查询一共有多少 ...
 - IOS Table中Cell的重用reuse机制分析
		
IOS Table中Cell的重用reuse机制分析 技术交流新QQ群:414971585 创建UITableViewController子类的实例后,IDE生成的代码中有如下段落: - (UITab ...
 - UITableViewCell的重用机制原理
		
UITableViewCell的重用机制原理 来自http://blog.csdn.net/omegayy/article/details/7356823 ====================== ...
 - [iOS基础控件 - 5.5] 代理设计模式 (基于”APP列表"练习)
		
A.概述 在"[iOS基础控件 - 4.4] APP列表 进一步封装,初见MVC模式”上进一步改进,给“下载”按钮加上效果.功能 1.按钮点击后,显示为“已下载”,并且不 ...
 - UITableViewCell在重用ID时为何加上Static关键字
		
UITableViewCell在重用ID时为何加上Static关键字 先回顾一下iOS各种变量作用域和生命周期相关知识: 1.方法中临时变量存储在栈区,出了该方法,临时变量会被自动销毁.但是如果给方法 ...
 - IOS基础学习-2: UIButton
		
IOS基础学习-2: UIButton UIButton是一个标准的UIControl控件,UIKit提供了一组控件:UISwitch开关.UIButton按钮.UISegmentedContro ...
 
随机推荐
- 【腾讯Bugly干货分享】iOS黑客技术大揭秘
			
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5791da152168f2690e72daa4 “8小时内拼工作,8小时外拼成长 ...
 - PostgreSQL基础整理(三)
			
1.触发器 有更新操作时记录一条日志 DROP FUNCTION IF EXIST log_test(); CREATE OR REPLACE FUNCTION log_test() RETURNS ...
 - 如何用MediaCapture解决二维码扫描问题
			
二维码扫描的实现,简单的来说可以分三步走:“成像”.“截图”与“识别”. UWP开发中,最常用的媒体工具非MediaCapture莫属了,下面就来简单介绍一下如何利用MediaCapture来实现扫描 ...
 - Java设计模式5:原型模式
			
原型模式 原型模式属于对象的创建模式,通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的用意. 原型模式结构 原型模式要求对象实现一个 ...
 - 设计模式之美:Template Method(模板方法)
			
索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Template Method 模式结构样式代码. 意图 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中. Templat ...
 - httpclient瓶颈
			
问题现象: 1.系统异常,应用拒绝访问. 2.web容器线程爆满 问题分析: 1.数据库正常 2.日志信息没有异常 问题思考: 1.应用访问量突破顶峰. 2.应用在某处存在瓶颈 发现问题: 需要了解线 ...
 - 冲刺阶段 day13
			
---恢复内容开始--- 项目进展 今天星期三,我们将专业管理部分又继续做了完善,之前漏掉的几项功也一一补全,没能实现的数据库部分也已经进行了完善,并且对已经完成的部分进行了检测,数据库的部分还有待进 ...
 - Gradle与Gatling脚本集成
			
Gatling作为次时代的性能测试工具,由于其API简洁明了.性能出众,越来越受欢迎.但是运行Gatling脚本却有诸多不便,其提供的默认方式不是很方便.考虑到Gatling脚本本质上是Scala类, ...
 - iOS instruments trace文件解析方案
			
前言 已很少写文章,不过这次感觉有必要写一下.因为: 1. 这个方案通过debug逆向得来,很有参考意义. 2. iOS这方面资料非常少,做这块时,无论国内外,翻遍了google,baidu都没太多合 ...
 - 实践基于Task的异步模式
			
Await 返回该系列目录<基于Task的异步模式--全面介绍> 在API级别,实现没有阻塞的等待的方法是提供callback(回调函数).对于Tasks来说,这是通过像ContinueW ...