【问题标题】:What is the exact order of UITableViewDelegate Methods - Strange behaviorUITableViewDelegate 方法的确切顺序是什么 - 奇怪的行为
【发布时间】:2017-11-02 06:42:58
【问题描述】:

我正在做一些研究以获取 tableview 委托方法的确切执行顺序。

案例 1:行数 - 用于小值

所以首先我创建了100 行并发现执行流程如下。

  1. numberOfSectionsInTableView
  2. numberOfRowsInSection
  3. cellForRowAtIndexPath

案例 2:行数 - 超过 Int 限制

我尝试返回大于 int 限制的值

然后发现抛出异常。效果很好。

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
 reason: 'Failed to allocate data stores for 402337200000000 rows in section 0.
 Consider using fewer rows'

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

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

当时需要超过 5 分钟,并且任何委托方法都在崩溃后被调用。在 cellForRowAt 被调用之前卡住了。我的系统也卡了这么长时间。崩溃时没有日志。

卡住时的内存使用情况

内存使用率变高

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

如果他们确定它会崩溃,那么这个范围应该包含在异常情况中。

那段时间他们有没有做其他事情?

在第 3 种情况下,编译器正在执行其他操作,并且“只有要在屏幕中显示的单元格才会为 tableview 加载”的概念失败。

【问题讨论】:

  • 只是 CPU 在表格视图中加载如此数量的单元格并导致崩溃和挂起系统。由于我的代码中存在无限循环,我也遇到了系统崩溃问题。所以,表视图委托和数据源方法没有问题。
  • 单元格将根据屏幕右侧的可用空间进行加载。那么为什么CPU会变高
  • @Saranjith 你在重复使用单元格吗?
  • @TusharSharma 是重复使用带有标识符的单元格
  • 在“numberOfRowsInSection”方法中使用断点。它也被调用 n 次(n = numberOfrowsinSection)。它在这种方法中崩溃了,这就是为什么不调用 cellForRowAtIndexpath 的原因。

标签: ios swift uitableview delegates


【解决方案1】:

您的问题标题“UITableViewDelegate 方法的确切顺序是什么”假定存在已定义的顺序。您确定的方法:

  • numberOfSectionsInTableView:
  • numberOfRowsInSection:
  • cellForRowAt:

实际上是在UITableViewDataSource protocol 中定义的,它没有提及调用方法的顺序。似乎有一个“逻辑”顺序,这大致就是您在 案例 1 中观察到的。但是,也有例外:在我的测试中,numberOfSectionsInTableView: 被连续调用两次,中间没有调用其他方法。

在您的 案例 2 中,您指定了大量的行,因此 tableView 会引发异常。这似乎可以理解:tableView 无法为所有这些行“分配数据存储”。如果它为每行存储 1 位信息,那就是 46 TB。它引发异常并不奇怪。

您的案例 3 显然是中间立场。为什么没有立即例外?谁知道。空间需求将是 468 GB,远远超过当前任何设备,但在几年后的可信度范围内。鉴于 iOS 运行在具有不同内存大小(一些 32 位、一些 64 位等)的许多不同设备上,Apple 开发人员不能对任何给定的行数“确定它会崩溃”。很明显,他们已经决定/默认尝试。

那么在调用numberOfRowsInSection 之后和调用cellForRowAt(或崩溃)之前发生了什么? tableView 显然正在尝试满足对这些行的请求。

UITableViewDelegate protocol 在“为表视图配置行”标题下定义了几种方法:

  • heightForRowAt:
  • estimatedHeightForRowAt:
  • indentationLevelForRowAt:
  • willDisplay:forRowAt:
  • 应该SpringLoadRowAt:with:

这些都是可选方法,但实施它们可能会为正在发生的事情提供一些线索。据我所知,heightForRowAtcellForRowAt 之后被调用(所以只有当一个单元格被分配给特定的行时)。但看起来estimatedHeightForRowAtnumberOfRowsInSection 之后和cellForRowAt 之前为每一行单独调用。

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

转向您的结论,“'只有要在屏幕中显示的单元格才会为 tableview 加载'的概念失败了”:请注意,正在使用的内存和花费的时间与 的数量有关行数,而不是单元格数。方法名均引用...*row*At。甚至 案例 2 中的例外情况也涉及 rows 的数据存储。如果您登录cellForRowAt,您将看到它只被调用了与屏幕上一样多的行,给或取几行,直到您滚动。滚动会导致单元格离开屏幕,此时 tableView 会将它们放入其队列中,以便为即将出现在屏幕上的一行重用(“出列”)。所以你的结论是错误的:单元格只为出现在屏幕上的行加载的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    • 1970-01-01
    • 2020-01-03
    相关资源
    最近更新 更多