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(0, 0, 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 60;
}

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 20;
}

-(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:


numberOfSectionsInTableView:调用栈信息.png


我们可以看到从addSubview是如何一步步调用到numberOfSectionsInTableView:的。
好的,我们下一步看断点断到了tableView:numberOfRowsInSection:上。


tableView:numberOfRowsInSection:调用栈信息.png


_rebuildGeometry这个私有方法之前都是一样的,所以我这里并没有全截,可以看到_rebuildGeometry中不仅调用了_updateRowData,还调用了一个_updateContentSize,从这里来获得每个section的行数。
我们接着往下看,到了tableView:heightForRowAtIndexPath:


tableView:heightForRowAtIndexPath:调用栈信息.png


这里通过了一个block回调的方式获取了各个row的高度,并决定了整个section的高度。
然后我们会发现,以上的几个方法还会再被调用一遍:


numberOfSectionsInTableView:调用栈信息2.png


但是栈信息已经不一样了,这次调用时由于tableview调用了layoutSubviews,而reloadData是layoutSubviews里调用的一个方法,因为layoutSubviews也是个公有的方法,所以我们可以用它来触发reloadData。
断点继续执行,就执行到了tableView: cellForRowAtIndexPath:,我们用它来获取tableview每个row的cell。


tableView: cellForRowAtIndexPath:调用栈信息.png


我们会发现tableView: cellForRowAtIndexPath:并不是靠_rebuildGeometry下面的方法来触发,而只是靠layoutSubviews来触发,如果layoutSubviews没有执行成功,那么就可能会遇到我之前遇到过的前几个方法执行而tableView: cellForRowAtIndexPath:不执行的问题。

    • 多了解UIKit的栈信息能够帮我们了解苹果运行的机制和原理,从而帮我们解决一些看起来非常诡异的bug,多看看苹果的私有方法也有助于我们养成良好的编程习惯,我们尽量模仿苹果的代码规范无论是对自己写代码看着舒服,还是对他人来读我们写的代码都一件好事。
posted @ 2016-12-01 17:03 倾剑飞血 阅读(913) 评论(0) 推荐(1) 编辑
摘要: 今年在做直播业务的时候遇到一些问题,就是在一个套播放器UI中需要多种不同的播放器(AVPlayer、IJKPlayer、AliPlayer)支持,根据ABTest开关来切换具体使用哪种播放器,并且还要对播放器进行日志统计。首先可以想到的是需要对不同的播放器封装一个统一的接口,对于UI来讲,不需要关系 阅读全文
posted @ 2016-11-24 13:21 倾剑飞血 阅读(792) 评论(0) 推荐(0) 编辑
摘要: 直播在2016年是一个非常火热的领域,我也有幸在今年参与了新浪微博直播客户端的开发,在此分享一下关于直播开发的一些经验。 1.视频直播的基本原理 视频直播的过程大概由这么几个部分构成: 推流端 源服务器 CDN边缘节点 播放端 直播架构.jpg 直播架构.jpg 整个直播流转的过程是:推流端将视频流 阅读全文
posted @ 2016-11-23 22:21 倾剑飞血 阅读(1681) 评论(4) 推荐(1) 编辑
摘要: 众所周知,iOS中提供了[UIDevice currentDevice].orientation与[UIApplication sharedApplication].statusBarOrientation这两种方式来获取设备的屏幕方向。其中UIDeviceOrientation包括以下几种枚举值t... 阅读全文
posted @ 2015-11-03 23:46 倾剑飞血 阅读(2461) 评论(0) 推荐(0) 编辑
摘要: 无论是在创业还是做一个单纯的产品设计时,我们都会采取借鉴他人的方式来解决当下遇到的问题。大多数人会根据存在即合理的原则,将市场上各种所谓之成功案例拼装在一起,当他们把这看似完美的杰作推向市场时,却发现这种东拼西凑不一定可以复制前人的成功。失败多次后,有人竟总结出复制成功是一门玄学的结论。那么我们... 阅读全文
posted @ 2015-10-31 17:37 倾剑飞血 阅读(1275) 评论(1) 推荐(0) 编辑
摘要: go语言在开发效率和运行效率中的优势让很多人青睐,所以有倾向打算转向go语言的开发。下面介绍在Mac OS X中golang的开发环境配置。1.安装brewbrew是一个mac下的由ruby开发的包管理系统,其官网是http://brew.sh。你只要在你的终端中执行ruby -e "$(curl ... 阅读全文
posted @ 2015-05-19 23:34 倾剑飞血 阅读(5093) 评论(1) 推荐(0) 编辑
摘要: 对于一个iOS app来讲,生命周期是一个十分至关重要的东西。对于一个app来讲控制着app的开启、睡眠、关闭等状态;对于一个页面的来讲,控制页面的加载、显示、消失;对于一个View或者一个普通的类来讲,控制着初始化、绘制、释放。一、AppDelegate当你创建一个iOS项目时,在appDeleg... 阅读全文
posted @ 2015-04-29 22:45 倾剑飞血 阅读(1059) 评论(0) 推荐(1) 编辑
摘要: 今天作为面试官第一次给别人面试。前一天的心情还比较忐忑,生怕被别人给问住了,毕竟我做ios的时间也不长,以前更多的经验是在做windows phone上。我前一天精心准备了几道面试题,有些考察基础知识,有些考察程序设计思路,笔试题总共13道,要求应试者做8道即可,因为即使再优秀的人也很难和你开发需求... 阅读全文
posted @ 2014-11-03 23:55 倾剑飞血 阅读(7913) 评论(46) 推荐(5) 编辑
摘要: 地球人找工作系列是本人去年毕业时,为本校学弟学妹们总结的一点求职心得。转眼一年了,很多人通过本文获得了帮助,所以今天拿出来与更多的朋友来分享。地球人找工作1之前期准备:http://www.cnblogs.com/jacklandrin/p/3866454.html地球人找工作2简历的秘密:http... 阅读全文
posted @ 2014-07-29 10:54 倾剑飞血 阅读(1610) 评论(5) 推荐(6) 编辑
摘要: 地球人找工作系列是本人去年毕业时,为本校学弟学妹们总结的一点求职心得。转眼一年了,很多人通过本文获得了帮助,所以今天拿出来与更多的朋友来分享。地球人找工作1之前期准备:http://www.cnblogs.com/jacklandrin/p/3866454.html地球人找工作2简历的秘密:http... 阅读全文
posted @ 2014-07-28 09:31 倾剑飞血 阅读(1344) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示