UITaleview - 关于执行顺序引发的探讨

UITableview优化这块,如果有心力的话是可以有很多东西去做处理的。本文目前仅就作为笔记,探讨一个方面。写这篇的文章来源于看到一篇博客,它里面先写了Tableview的两个主要协议,再通过两个协议执行方法去分析优化的方面。
上链接详细整理:UITableView优化技巧

它就Tableview的两个主要协议谈到了几点:

知道UITableViewCell的重用原理后,我们来看看UITableView的回调方法。UITableView最主要的两个回调方法是tableView:cellForRowAtIndexPath:和tableView:heightForRowAtIndexPath:。理想上我们是会认为UITableView会先调用前者,再调用后者,因为这和我们创建控件的思路是一样的,先创建它,再设置它的布局。但实际上却并非如此,我们都知道,UITableView是继承自UIScrollView的,需要先确定它的contentSize及每个Cell的位置,然后才会把重用的Cell放置到对应的位置。所以事实上,UITableView的回调顺序是先多次调用tableView:heightForRowAtIndexPath:以确定contentSize及Cell的位置,然后才会调用tableView:cellForRowAtIndexPath:,从而来显示在当前屏幕的Cell。
举个例子来说:如果现在要显示100个Cell,当前屏幕显示5个。那么刷新(reload)UITableView时,UITableView会先调用100次tableView:heightForRowAtIndexPath:方法,然后调用5次tableView:cellForRowAtIndexPath:方法;滚动屏幕时,每当Cell滚入屏幕,都会调用一次tableView:heightForRowAtIndexPath:、tableView:cellForRowAtIndexPath:方法。

看到他写的很详细,比较容易懂。 本人就着这个博客顺手写个小demo测试了一下它的执行顺序及次数。

注:
环境:macOS High Sierra 10.13.6 - Xcode 10.1(10B61) - swift4.2
tableview和cell用storyboard和xib实现,下面为部分关键代码

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("行数 ……………… 超1屏")
        return 60 ;
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        print("高度 --- 超1屏")
        return 1000;
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        print("cell")
        let cel = tableView.dequeueReusableCell(withIdentifier: "MyCell") as! MyCell
        return cel
    }

这个程序,如果按照那篇博客的说法应该是先调用了60次heightForRowAt 然后调用1次cellForRowAt。那么我实验的结果是:每次先调用3次numberOfRowsInSection,之后交互调用1次cellForRowAt和heightForRowAt,总共调
用15次,滑动的时候会依次调用cellForRowAt和heightForRowAt
单个cell超过1个屏幕

这个结果和博客的结果显然有些出入。 不过,结果不一致不代表那个文章就是错的。我读了后面的评论看到以下内容: 博客截图

是的,有人跟我一样去做了测试,并且也发现不一致了。因此可以推断,他当时写那篇博客的时候,可能就是那样的执行顺序,只是后面苹果又对其进行改变策略而已。结果对我们来说,已经很明了了。那目前版本执行的顺序又是什么样子的呢?我来测试看看。为了查看更多执行顺序,我把分组和行的方法都写下来:
先来测试 这个方法

   func numberOfSections(in tableView: UITableView) -> Int 

关键代码

    func numberOfSections(in tableView: UITableView) -> Int {
        print("Sections")
        return 1;
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("行数 ……………… 1屏")
        return 6 ;
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        print("高度 --- 少1屏")
        return 100;
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        print("cell")
        let cel = tableView.dequeueReusableCell(withIdentifier: "MyCell") as! MyCell
        return cel
    }
    

输出结果1
结果如图:sections执行了3次。

把高度调小到1,然后再执行,发现还是结果如上图:sections执行了3次。

为了方便调试测试,我把分析的各个变量和结果做成一张表格
输出结果

excel表格在后面附上链接,有兴趣的可以下载查看一下内容。

总结起来就是:

1.从执行顺序上看,这几个协议方法的执行顺序是:
numberOfSections 然后numberOfRowsInSection然后cellForRowAt最后heightForRowAt
2.从执行次序上看:
numberOfSections 每次执行3次且必执行3次
numberOfRowsInSection有多少执行多少
cellForRowAt如果所有cell的屏幕高度总和小于屏幕,则全部执行,如果总和大于屏幕,则只执行15次。
3.滑动执行顺序:是先cell再执行高。且交替执行
4.numberOfSections和numberOfRowsInSection交替执行3次,每次执行1次numberOfSections和所有次numberOfRowsInSection,执行完之后才交替执行cellForRowAt和heightForRowAt

不排除如果用代码实现的话,它执行顺序又有出入的情况。(后面有时间再测试)

至于为什么numberOfSections执行3次,cellForRowAt执行15次,应该是苹果那边的缓存机制。有其他见解的欢迎探讨。

有兴趣的人也可以进群讨论技术,技术讨论问题请加 群Q号:201708926

excel统计结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值