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层架构的 ...
随机推荐
- mono for android中使用dapper或petapoco对sqlite进行数据操作
在mono for android中使用dapper或petapoco,很简单,新建android 类库项目,直接把原来的文件复制过来,对Connection连接报错部分进行注释和修改就可以运行了.( ...
- 【Win10】UAP/UWP/通用 开发之 x:Bind
[Some information relates to pre-released product which may be substantially modified before it's co ...
- AngularJS 第三天----作用域
作用域的概念及其功能 AngularJS使用作用域的概念来充当数据模型的作用,在视图和控制器之间起着桥梁的作用.由于双向绑定的数据特性,视图的修改会更新 $scope,同样对 $scope的修改也会重 ...
- Guava库介绍之实用工具类
作者:Jack47 转载请保留作者和原文出处 欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 本文是我写的Google开源的Java编程库Guava系列之一,主要介 ...
- ValueInjecter----最好用的OOM(以微信消息转对象举例)
使用数据实体的好处我这里就不多说了,但大家享受这些好处的时候,难免也对那些琐碎的赋值代码感到厌烦,基于此,我认为掌握一个oom的使用,还是很有必要的. 这种类型的工具有很多,比如automapper, ...
- ASP.NET MVC 描述类型(一)
ASP.NET MVC 描述类型(一) 前言 在前面的好多篇幅中都有提到过ControllerDescriptor类型,并且在ASP.NET MVC 过滤器(一)篇幅中简单的描述过,今天我们就来讲一下 ...
- 从EF的使用中探讨业务模型能否脱离单一存储层完全抽象存在
上次赶时间,就很流水账地写了上次项目对EF的一次实践应用模式,因为太长了,也没能探讨太多,所以再继续扩展. 这次想探讨的是,实体,如果作为类似于领域模型的业务模型存在,它的数据能否来自不同的数据源.这 ...
- jQuery选择器中,通配符[id^='code']input[id$='code'][id*='code']
1.选择器 (1)通配符: $("input[id^='code']");//id属性以code开始的所有input标签 $("input[id$='code']&qu ...
- MySQL中You can't specify target table for update in FROM clause一场
mysql中You can't specify target table <tbl> for update in FROM clause错误的意思是说,不能先select出同一表中的某些值 ...
- ActiveMQ的集群方案对比及部署
转载:http://blog.csdn.net/lifetragedy/article/details/51869032 ActiveMQ的集群 内嵌代理所引发的问题: 消息过载 管理混乱 如何解决这 ...