浅析UITableView的Cell复用机制 dequeueReusableCell

前言:

在承载大容量条目信息时,UITableView(或UICollectionView)的复用机制扮演者不可或缺的角色。iOS自动地为我们将cell从cell队列里入队和出队操作,本文将浅析这一机制。

创建cell的方法:

在实现了UITableViewDataSource这一协议后,回调方法 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell内我们可以进行cell的注册及其初始化编写。为了简单起见,这里使用系统提供的cell类。

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "REUSABLE_CELL_ID", for: indexPath)
       
        cell.textLabel?.text = "FIX TEXT."
        
        return cell
    }

这是一个最为简单的cell了。有多个不同的tableview则由其对象来进行区分。

Reusable机制:

单独几个或几十个数据是看不出来Reusbale机制的优势,所以在这里定义其数目为1000个,这样的大容量条目很容易通过是否卡顿来看出其优劣的。

Reusable机制其实内部是通过一种cell队列(具体叫什么不知道,但可以猜出来肯定存在)的东西实现的。我们通常使用的dequeueReusableCell的dequeue其实就是出队列操作。从哪里出队列呢?就是cell队列。我们可以将cell对象的绘制简单地归纳如下:

  1. 初次执行cell绘制回调方法会直接根据Identifier直接绘制屏幕内最大所能显示cell数目数量的cell对象
  2. 如果屏幕滑动,系统就会将已创建但从屏幕上被移除的cell对象放入cell队列里面;但有放就有取,当屏幕滑动时新的cell对象就会从cell队列取出
  3. 根据第二步,如果有可被复用的cell,那么新展示的cell可直接使用,没有的话就只能直接创建新的cell。然而新创建cell这种情况多发生于界面刚出现,也就是说正常情况下新的cell是要从cell队列里取出的(如果存在)

实验:

为了验证Reusable机制的存在,我们可以通过内存、CPU、磁盘、cell对象的地址分别进行判断。

内存:

启动模拟器,待屏幕内cell加载完毕立即滑动到第1000个。这里不用采用其它方法来直接滑动到第1000个(因为是模拟普通用户的操作,正常情况下普通用户是无法直接滑动到第1000个cell)下同。
在这里插入图片描述
Memory坐标轴显示,在极端时间内(约4s)系统就绘制了1000个cell,然而其内存峰值是在第三个波峰(前两个端点是VC启动时),约为49.7MB。在Android里面曾经我做过一个这样的实验:横向放置一个RecyclerView,item数目为5,内为纯ImageView,分辨率为1920*1080,加载完毕后其内存达到了惊人的580MB。所以在这里不得不佩服其Reusable机制。

CPU:

启动模拟器,待屏幕内cell加载完毕立即滑动到第1000个。
在这里插入图片描述
第一个波峰为启动第一个VC,第二个为启动第二个VC附加绘制1000个cell。

我们重点看第二个波峰。第二个波峰其实是有左侧一个很小的波峰以及右侧一个大波峰构成。左侧很小的波峰是启动VC时所消耗的CPU资源,右侧则是创建TableView、绘制在屏幕内最大显示的cell数目的cell、放入cell队列所消耗的CPU资源。文章前部分已指出,绘制1000个cell其实是仅绘制了在屏幕内能显示最大数目的cell,那么其余的cell数目 = 数据源数目 - 屏幕内最大能显示cell数目。我们肯定是希望左侧值越大越好,而恰恰一个屏幕内最大能显示cell数目在正常情况下是很小的,所以Reusable机制的出现也是理所当然。

磁盘:

启动模拟器,待屏幕内cell加载完毕立即滑动到第1000个。
在这里插入图片描述

cell对象:

启动模拟器,待屏幕内cell加载完毕立即滑动到第1000个。这里需要做一个小的内容。我们可以先创建一个泛型集合,参数为UITableViewCell。每当系统回调 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell该方法时,我们就将从cell队列里取出的cell放入该泛型集合内,待该集合的cout大于20时,此时迭代该泛型集合内的cell地址。

先定义类变量:

var varifyArray: Array<UITableViewCell> = []

然后在回调方法内迭代cell地址:

        varifyArray.append(cell)
        
        if indexPath.row > 20 {
            for _ in 0..<varifyArray.count{
                print(varifyArray[indexPath.row])
            }
        }

迭代内容如下:
在这里插入图片描述
我们可以看到,其前20个cell地址均为0x7fd641e47ff0,也就是说前20个cell的内存地址是指向同一个地方的。这也就从内存方面佐证了Reusable机制内cell是复用的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值