UITableview delegate dataSource调用探究
UITableview是大家常用的UIKit组件之一,使用中我们最常遇到的就是对delegate和dataSource这两个委托的使用。我们大多数人可能知道当reloadData这个方法被调用时,delegate和dataSource就会被回调,但是其中具体的细节,可能很多人不会去探究。
我最近有兴趣来探讨这个问题是因为我最近遇到过dataSource中有的方法被调用,但是有的方法没有被调用的情况,同时你会发现当tableview被add到一个superView的时候,也会触发了reloadData一样的回调。那么这两个委托究竟是怎么执行的呢?
我们首先来看看苹果文档对reloadData的描述
Call this method to reload all the data that is used to construct the table,
including cells, section headers and footers, index arrays, and so on. For
efficiency, the table view redisplays only those rows that are visible. It adjusts
offsets if the table shrinks as a result of the reload. The table view’s delegate or
data source calls this method when it wants the table view to completely reload
its data. It should not be called in the methods that insert or delete rows,
especially within an animation block implemented with calls to beginUpdates and
endUpdates.大致的意思就是说reload这个方法是用来构建table的,包括cell、section,而且只会对可见的行进行重新的绘制,当tableview想要完整的加载数据时,delegate和data source会调用此方法。增加删除行,尤其是需要block动画的时候不用用它。
从这里只能看出个大概,并没有解释调用的原理。那么让我们先写一个最基本的tableview实现,然后对delegate和data source的回调设置一下断点看看。
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(, , self.view.bounds.size.width, self.view.bounds.size.height)];
tableView.delegate = self;
tableView.dataSource = self;
[self.view addSubview:tableView];
// [tableView reloadData];
// [tableView layoutSubviews];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return ;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return ;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return ;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellID = @"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if(!cell){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.textLabel.text = @"哈哈";
return cell;
}
我们先对下面这四个方法设置一下断点,然后观察左边的栈信息。
首先被调用的是numberOfSectionsInTableView:
我们可以看到从addSubview是如何一步步调用到numberOfSectionsInTableView:的。
好的,我们下一步看断点断到了tableView:numberOfRowsInSection:上。
_rebuildGeometry这个私有方法之前都是一样的,所以我这里并没有全截,可以看到_rebuildGeometry中不仅调用了_updateRowData,还调用了一个_updateContentSize,从这里来获得每个section的行数。
我们接着往下看,到了tableView:heightForRowAtIndexPath:
这里通过了一个block回调的方式获取了各个row的高度,并决定了整个section的高度。
然后我们会发现,以上的几个方法还会再被调用一遍:
但是栈信息已经不一样了,这次调用时由于tableview调用了layoutSubviews,而reloadData是layoutSubviews里调用的一个方法,因为layoutSubviews也是个公有的方法,所以我们可以用它来触发reloadData。
断点继续执行,就执行到了tableView: cellForRowAtIndexPath:,我们用它来获取tableview每个row的cell。
我们会发现tableView: cellForRowAtIndexPath:并不是靠_rebuildGeometry下面的方法来触发,而只是靠layoutSubviews来触发,如果layoutSubviews没有执行成功,那么就可能会遇到我之前遇到过的前几个方法执行而tableView: cellForRowAtIndexPath:不执行的问题。
- 多了解UIKit的栈信息能够帮我们了解苹果运行的机制和原理,从而帮我们解决一些看起来非常诡异的bug,多看看苹果的私有方法也有助于我们养成良好的编程习惯,我们尽量模仿苹果的代码规范无论是对自己写代码看着舒服,还是对他人来读我们写的代码都一件好事。
UITableview delegate dataSource调用探究的更多相关文章
- Swift_TableView(delegate,dataSource,prefetchDataSource 详解)
Swift_TableView(delegate,dataSource,prefetchDataSource 详解) GitHub import UIKit let identifier = &quo ...
- C# Delegate 异步调用
namespace ConsoleApplication22 { /// /// 异步操作 /// /// /// /// //internal Func<int,int,int> int ...
- UITableView 接口的调用顺序
ios7启用estimatedHeightForRowAtIndexPath之后的api调用顺序called -[XHYTableViewController tableView:heightForR ...
- 快速设置UITableView不同section对应于不同种类的cell
快速设置UITableView不同section对应于不同种类的cell 本文主要是为了写明如何在UITableView中,一个section对应于一种类型的cell,写起来不凌乱. 在不封装任何类的 ...
- 解决tableView中cell动态加载控件的重用问题
解决tableView中cell动态加载控件的重用问题 tableView的cell,有时候需要在运行时取得对应的数据后才能够动态的创建该cell中的控件并加载到该cell中,此时,你一定会遇到重用问 ...
- 更新tableView的某个cell
更新tableView的某个cell 异步加载完数据后更新某个cell,这应该是非常常见的使用方法了,我们经常会用reloadData. 效果: 源码: // // RootViewControlle ...
- iOS基础 - UITableView的数据源(dataSource)和代理(delegate)
UITableView的数据源(dataSource)和代理(delegate) UITableView需要一个数据源(dataSource)来显示数据,UITableView会向数据源查询一共有多少 ...
- 教你写能被舒服舒服又舒服地调用的iOS库
目录 前言 脑洞开一开 分析 整容 结语 前言 2014年过的那么快,过年又那么块,2015年又是飞快地节奏,真尼玛感觉上帝是不是无聊使用了变速外挂开启了加速模式~到现在博主都无法接受已经上班的事实… ...
- iOS应用架构谈(三):View层的组织和调用方案(下)
iOS客户端应用架构看似简单,但实际上要考虑的事情不少.本文作者将以系列文章的形式来回答iOS应用架构中的种种问题,本文是其中的第二篇,主要讲View层的组织和调用方案.下篇主要讨论做View层架构的 ...
随机推荐
- ENode框架单台机器在处理Command时的设计思路
设计目标 尽量快的处理命令和事件,保证吞吐量: 处理完一个命令后不需要等待命令产生的事件持久化完成就能处理下一个命令,从而保证领域内的业务逻辑处理不依赖于持久化IO,实现真正的in-memory: 保 ...
- MySQL8:连接查询
连接查询 连接是关系型数据库模型的主要特点. 连接查询是关系型数据库中最主要的查询,主要包括内连接.外连接等通过联结运算符可以实现多个表查询. 在关系型数据库管理系统中,表建立时各种数据之间的关系不必 ...
- 前端自学路线之js篇
上一篇我们讲了前端切图的学习路线,不知大家有没有收获.今天来聊聊前端工程师的核心技能之——JavaScript.js这门语言看似简单,但要做到入门.熟练以至于架构的程度,还是有一段路要走的,今天就来聊 ...
- 2000条你应知的WPF小姿势 基础篇<22-27 WPF生命周期, 基础类等>
端午长假在家陪着女朋友, 幸福感满满,生活对于一只饱经忧患的程序猿来说也是非常重要的,也就暂时没有更新博客.休假结束,回归奋斗的日子了,开始继续更新WPF系列. 在正文开始之前需要介绍一个人:Sean ...
- 玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理
Windows服务Debug版本 注册 Services.exe -regserver 卸载 Services.exe -unregserver Windows服务Release版本 注册 Servi ...
- Android开发学习之路-LeakCanary使用
LeakCanary是一个内存泄漏检测库,它可以在我们的应用发生内存泄漏的时候发出提醒,提醒包括通知和Log.GitHub 这个库使用起来比较简单: ①添加依赖: dependencies { deb ...
- javascript中的Function和Object
写的很好,理解了很多,特此转发记录 转自:http://blog.csdn.net/tom_221x/archive/2010/02/22/5316675.aspx 在JavaScript中所有的对象 ...
- 01.Web大前端时代之:HTML5+CSS3入门系列~初识HTML5
Web大前端时代之:HTML5+CSS3入门系列:http://www.cnblogs.com/dunitian/p/5121725.html 文档申明 <!--文档类型申明,html代表是ht ...
- 日常css技巧小结(1)--背景透明度改变对内容无影响
刚开始出现的错误,内容会受到背景透明度改变的影响:如图: 代码: <!DOCTYPE html> <html lang="en"> <head> ...
- C# 设置Excel打印选项及打印excel文档
C# 设置Excel打印选项及打印excel文档 打印Excel文档是一个很常见的操作,但有时候我们会碰到各种不同的打印需求,例如只打印一个Excel工作表的其中一部分,或打印时每页都有表头,或把工作 ...