UITableViewDelegate方法的确切顺序是什么 - 奇怪的行为

Sar*_*ith 6 delegates uitableview ios swift

我做了一些研究,以获得tableview委托方法的确切执行顺序.

案例1:行数 - 对于小值

首先,我创建了100行,并找到了如下的执行流程.

  1. numberOfSectionsInTableView
  2. numberOfRowsInSection
  3. 的cellForRowAtIndexPath

案例2:行数 - 高于Int限制

我尝试返回大于int limit的值

然后发现一个异常抛出.效果很好.

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
 reason: 'Failed to allocate data stores for 402337200000000 rows in section 0.
 Consider using fewer rows'
Run Code Online (Sandbox Code Playgroud)

案例3:行数 - Int值但更高

之后我将行数更改为4023372000000理想值,但确认返回类型为Int.

那时它需要超过5分钟,并且任何委托方法在被崩溃后被调用.在被叫之前被卡住了.我的系统也停留了很长时间.没有登录崩溃.

卡住期间的内存使用量

内存使用率很高

可用空间= -50GB(也使用我的系统内存)百分比使用率= 600%

如果他们确定它会崩溃,那么这个范围应该包含在Exception案例中.

他们在那段时间做了别的事吗?

在第3种情况下,编译器正在执行其他操作,并且"只有要在屏幕中显示的单元格将被加载以进行tableview"的概念失败.

pba*_*sdf 6

您的问题标题"UITableViewDelegate方法的确切顺序是什么",假定存在已定义的顺序.您确定的方法:

  • numberOfSectionsInTableView:
  • numberOfRowsInSection:
  • cellForRowAt:

实际上是在UITableViewDataSource协议中定义的,它没有提到调用方法的顺序.似乎有一个"逻辑"的顺序,这大致是你在案例1中观察到的.但是,有一些例外:在我的测试中,numberOfSectionsInTableView:连续两次调用,而不会在其间调用其他方法.

在您的案例2中,您指定了大量的行,因此tableView会抛出异常.这似乎是可以理解的:tableView无法为所有这些行"分配数据存储".如果每行甚至存储1位信息,则为46TB.它并没有引起异常.

你的案例3显然是中间立场.为什么没有立即例外?谁知道.空间要求将是468千兆字节,远远超过任何现有设备,但在几年内可信度范围内.鉴于iOS运行在具有不同内存大小的许多不同设备上,大约32位,大约64位等,Apple开发者无法在任何给定数量的行中"确定它会崩溃".很明显,他们决定/拖欠尝试.

那么在呼叫之后numberOfRowsInSection和呼叫cellForRowAt(或崩溃)之前发生了什么?tableView显然正在尝试完成对这些行的请求.

所述的UITableViewDelegate协议定义的标题的"配置表视图行"下几种方法:

  • heightForRowAt:
  • estimatedHeightForRowAt:
  • indentationLevelForRowAt:
  • willDisplay:forRowAt:
  • shouldSpringLoadRowAt:其中:

这些都是可选方法,但实现它们可能会给出一些关于发生了什么的线索.从我所看到的,heightForRowAt被称为之后cellForRowAt(所以只有当一个单元格被分配到特定行时).但它看起来像是estimatedHeightForRowAt分别为每一行,之后numberOfRowsInSection和之后分别调用cellForRowAt.

为什么在为一个单元加载单元格之前,tableView是否应该知道所有行的估计高度?我的猜测是tableView正在尝试确定它的整体contentSize:将所有行的高度相加以获得总高度.实现estimatedHeightForRowAt显然是增加了tableView的工作并因此减慢了速度,但即使你没有实现该方法,tableView也必须做一些事情来计算每一行的高度:这需要时间和内存.

转到你的结论,"概念'只有要在屏幕上显示的单元格才会被加载以进行查看'失败":请注意,正在使用的内存和所用的时间与数有关,而不是与数有关.细胞.方法名称全部引用...*row*At.即使案例2中的例外也引用了的数据存储.如果你记录,cellForRowAt你会看到它只被调用为屏幕上的行数,给予或采取一对,直到你滚动.滚动导致单元格离开屏幕,此时tableView将它们放入其队列中,准备重新使用("出列")一行即将出现在屏幕上.所以,你的结论是错误的:细胞只加载出现在屏幕上的行.