.reloadData() 没有重新创建可见单元格或内存中的单元格?

.reloadData() without reCreating visible cells or those who are in memory?

当我实例化了第三个单元格后,我会将更多项目添加到我的模型数组中,然后我将更新集合视图数据:

DispatchQueue.main.async(execute:  {
    self.collectionView.reloadData()
})

一切正常。但是,当我为 collectionView 重新加载数据时,它将实例化当前可见或保存在内存中的单元格 (2,3)。不幸的是,我有一些昂贵的服务器请求会消耗大量时间。

Instaniated  0
Instaniated  2
Instaniated  3

******polluting more data: size of cells 10

Instaniated  2
Instaniated  3
Instaniated  4

如何在不重新创建可见单元格或内存中的单元格的情况下重新加载数据?

非常感谢。

不要重新加载单元格,而是尝试插入或重新加载实际已更改的单元格。您可以为此使用 UIColletionViews performBatchUpdates(_:)Link

一个例子:

collectionView.performBatchUpdates {
  self.collectionView.insertItems(at: [IndexPath(row: 1, section: 1)])
}

这样可以确保只加载新的单元格。您还可以在此方法中移动单元格和部分,甚至删除单元格。链接页面包含所有这些的文档。

为什么你不能使用下面的方法

1) 我希望您已将 dataSource 和 collectionView 对象声明为 class

的全局对象
let collectionView = UICollectionView()
var dataSource = [Any]()

2) 有一个函数可以从 API 响应

中获取初始结果
func getInitialPosts(){
    // call api
    // store your initial response in the local array object and reload collectionview
    let results:[Any] = {response from the server call}
    self.dataSource.append(contentsOf: results)
    DispatchQueue.main.async(execute: {
        self.collectionView.reloadData()
    })
}

3) 下次调用,可以有另一个函数

func getPostsForPage(page:Int){
    // call api with page number
    let newResults = {response from the server call}
    self.dataSource.append(contentsOf: newResults)

    var indexPathsToReload = [IndexPath]()
    let section = 0
    var row = self.dataSource.count - 1

    //add new data from server response
    for _ in newResults {
        let indexPath = IndexPath(row: row, section: section)
        row+=1
        indexPathsToReload.append(indexPath)
    }

    // perform reload action
    DispatchQueue.main.async(execute: {
        self.collectionView.insertItems(at: indexPathsToReload)
    })
}

假设您从您的网络适配器调用委托函数 fetchData 使用新数据。在这里你必须检查你的数据是否为空,检查你是否需要添加新数据,或者重新加载整个 CollectionView。

然后你创建所有你需要获取更多的indexPaths,为了让已经获取的单元格保持原样。最后使用 insertItems(at: IndexPaths).

我使用 page 是为了将来用页码对新数据进行分页。严格针对我的用例。祝你好运!

func fetchData(with videos: [VideoModel], page: Int) {
    guard self.data.count == 0 else{
        self.addNewData(with: videos, page: page)
        return
    }
    self.data = videos
    DispatchQueue.main.async {
        self.isPaging = false
        self.collectionView?.reloadData()
        self.page = page
    }
}
func addNewData(with videos: [VideoModel], page: Int){
    var indexPathsToReload = [IndexPath]()
    let section = 0
    var row = self.data.count - 1
    self.data += videos
    for _ in videos {
        print(row)
        let indexPath = IndexPath(row: row, section: section)
        row+=1
        indexPathsToReload.append(indexPath)
    }
    DispatchQueue.main.async{
        self.isPaging = false
        self.collectionView!.insertItems(at: indexPathsToReload)
        self.page = page
    }
}