有没有办法预加载 UICollectionViewCell?

Is there a way to -preload- UICollectionViewCell?

困扰我很久的事情

有没有预加载 UICollectionViewCell 的方法? 在加载数据之前需要准备一些东西,因此在用户滚动时不会创建单元格。

有没有办法完全控制何时创建 UICollectionViewCell 和何时销毁 UICollectionViewCell。

来自Apple documentation

You typically do not create instances of this class yourself. Instead, you register your specific cell subclass (or a nib file containing a configured instance of your class) with the collection view object. When you want a new instance of your cell class, call the dequeueReusableCell(withReuseIdentifier:for:) method of the collection view object to retrieve one.

cell 本身并不是一个沉重的资源,所以定制它的生命周期是有一点意义的。 我认为与其寻找一种方法来控制单元格的创建,不如问问自己:为什么要预加载单元格?你想预加载什么样的重资源? 根据答案,您可以尝试以下优化:

  • 如果您的单元格中有复杂的视图层次结构,请考虑从自动布局重构为手动设置框架
  • 如果您的单元格应该显示一些复杂计算或远程图像的结果,您希望有一个单独的架构层来加载这些资源,并且无论如何都不应该在单元格 class 中进行。必要时使用缓存。

您可以在进入场景并导航(滚动)到每个单元格类型时关闭屏幕。当您确实滚动每个单元格时,您应该隐藏遮光视图并在第一个单元格(顶部)上呈现集合视图。

这是某种解决方法。我的单元格有很多资源,例如图像,在滚动集合视图时会滞后。

我可以添加一些实际的方法

如果您需要从互联网/核心数据结帐中预加载一些数据https://developer.apple.com/documentation/uikit/uicollectionviewdatasourceprefetching/prefetching_collection_view_data

tl;dr

首先 除了 UICollectionViewDataSource 协议之外,您还需要集合视图数据源符合 UICollectionViewDataSourcePrefetching

然后 预取您的数据并将其存储在缓存中

func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
    // Begin asynchronously fetching data for the requested index paths.
    for indexPath in indexPaths {
        let model = models[indexPath.row]
        asyncFetcher.fetchAsync(model.id)
    }
}

最后 将缓存数据提供给您的单元格

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Cell.reuseIdentifier, for: indexPath) as? Cell else {
        fatalError("Expected `\(Cell.self)` type for reuseIdentifier \(Cell.reuseIdentifier). Check the configuration in Main.storyboard.")
    }

    let model = models[indexPath.row]
    let id = model.id
    cell.representedId = id

    // Check if the `asyncFetcher` has already fetched data for the specified identifier.
    if let fetchedData = asyncFetcher.fetchedData(for: id) {
        // The data has already been fetched and cached; use it to configure the cell.
        cell.configure(with: fetchedData)
    else
        ... async fetch and configure in dispatch main asyncd

另外您可以使用委托方法来处理 willDisplay、didEndDisplay 事件,例如https://developer.apple.com/documentation/uikit/uicollectionviewdelegate/1618087-collectionview?language=objc