加载 UITableView 或 UICollectionView 上的可见单元格

Getting loaded vs visible cells on a UITableView or UICollectionView

随着 iOS 10 的推出,我们似乎将拥有 prefetching enabled by default on UITableView and UICollectionViews。这意味着未显示在屏幕上的单元格将在用户实际看到它们之前被提取。

下面是一些相关的方法:

UITableView:

UICollectionView:

所有这些都在描述中特别提到了"visible"。随着 iOS 10 中预取功能的引入,我如何区分预取的单元格与当前可见的单元格?

换句话说:

  1. 如何获取所有可见单元格?
  2. 如何获取所有加载的单元格?

UITableView 或 UICollectionView 上似乎没有任何新的 API 可以帮助解决这个问题。

TL;DR

  • 按字面理解函数名中的visible
  • UITableView 的行为与在 iOS 9 中一样。
  • 如果您想在 iOS 10 上以不同方式处理 UICollectionView 中加载的单元格和可见单元格,则需要做一些簿记工作。

UITableView 和 UICollectionView 在预取方面表现得非常不同。

首先要注意的是,预取 cells 和预取 data:

是有区别的
  • 预取单元格指的是在单元格实际显示在屏幕上之前调用cellForRowAtIndexPath。这会启用您的单元格在屏幕外但仍处于加载状态的情况。
  • 预取数据 指的是 prefetchDataSource 方法,它通知您 indexPaths 将要显示在屏幕上。调用此方法时您没有对单元格的引用,并且调用此方法时您没有 return 单元格。相反,此方法应该执行诸如触发网络请求以下载将在单元格中显示的图像之类的事情。

注意:在所有这些场景中,假设有 8 个单元格可以在任何给定时间显示。

UITableView:(选项:no prefetching,或prefetch data

  • 永远不会预取 单元格 。换句话说,它永远不会在未显示的 indexPath 上调用 cellForRowAtIndexPath
  • 因此,UITableView 上没有 isPrefetchingEnabled 属性。
  • 您可以使用 prefetchDataSource.
  • 选择预取 数据
  • 请注意,虽然 table 视图看起来确实是 less aggressive with reusing cells,但当重复使用的单元格返回屏幕时,它似乎仍然调用 cellForItemAtIndexPath。 (尽管我可能需要对此做更多调查,尤其是对于集合视图。)

UICollectionView:(选项:no prefetchingprefetch cellsprefetch cells and data

  • 默认预取 单元格 。换句话说,它将为不会立即显示的单元格调用 cellForItemAtIndexPath
  • 仅当用户在集合视图上向上或向下滚动时才会开始预取单元格。换句话说,当加载视图时,您将得到对 cellForItemAtIndexPath 的恰好 8 次调用。只有当用户向下滚动时,它才会开始询问不可见的单元格(例如,如果您向下滚动以显示 2-10,它可能会询问 11-14)。
  • 当预取的、不可见的单元格出现在屏幕上时,它不会再次调用 cellForItemAtIndexPath。它将假定您第一次进行的实例化仍然有效。
  • 您可以使用 prefetchDataSource.
  • 选择预取 数据
  • prefetchDataSource 结果证明只对初始加载有用。在上面的相同场景中,当显示前 8 个单元格时,它可能会触发预取单元格 9-14 的数据,例如。但是,一旦调用了这个初始方法,此后就没有用了。这是因为 cellForItemAtIndexPath 将在每次调用 prefetchItemsAt 后立即被调用。例如,您会得到 prefetchItemsAt:[14, 15] 紧跟 cellForItemAt:14cellForItemAt:15.
  • 您可以通过设置 isPrefetchingEnabled = false 选择退出 所有 预取行为。这意味着您不能使 UICollectionView 的行为类似于具有 prefetchDataSource 的 UITableView。或者,换句话说,你不能只有一个 UICollectionView prefetch data

对于两者:

  • visibleCellsindexPathsForVisibleRowscellForItemAtIndexPath 就像他们说的那样:它们只处理 可见的 细胞。在我们的相同场景中,如果我们加载了 20 个单元格,但只有 8 个单元格在屏幕上可见。所有这 3 种方法都只会报告屏幕上的 8 个单元格。

那么这是什么意思?

  • 如果您使用的是 UITableView,则可以按原样使用它,而不必担心加载单元格与可见单元格之间的差异。它们总是等价的。
  • 另一方面,对于 UICollectionView,如果您关心这种差异,则需要做一些簿记以跟踪加载的不可见单元格与可见单元格。您可以通过查看数据源上的一些方法和委托方法(例如 willDisplayCell、didEndDisplayingCell)来做到这一点。