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

Posted

技术标签:

【中文标题】.reloadData() 没有重新创建可见单元格或内存中的单元格?【英文标题】:.reloadData() without reCreating visible cells or those who are in memory? 【发布时间】:2018-02-07 12:31:33 【问题描述】:

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

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

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

非常感谢。

【问题讨论】:

然后缓存来自 API 的响应,如果每次都重新获取成本太高。 【参考方案1】:

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

一个例子:

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

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

【讨论】:

感谢您的帮助! - 不幸的是,我收到以下错误:更新后现有部分中包含的项目数 (10) 必须等于更新前该部分中包含的项目数 (5),加上或减去插入的项目数或从该部分中删除。 @JulieNoobie 您在数组中的相同索引处插入了相同的值,因此numberOfCells 计数也是可维护的,并且您的数据数组的顺序与您希望在 tableView 上表示的顺序相同。希望你能明白。【参考方案2】:

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

1) 我希望您已将 dataSource 和 collectionView 对象声明为类的全局对象

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)
    )

【讨论】:

【参考方案3】:

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

然后,您创建所有需要获取更多的 indexPath,以便让已获取的单元格保持原样。最后使用 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
    

【讨论】:

以上是关于.reloadData() 没有重新创建可见单元格或内存中的单元格?的主要内容,如果未能解决你的问题,请参考以下文章

使用自我调整大小的单元格后,reloadData 不再起作用

UITableView, reloadData 重新加载单元格但不调整表格大小

iOS - [UITableView reloadData] 重新加载,但不删除旧单元格?

UITableView ReloadData 动画单元格 UI

在表格视图中重新加载数据而不损害动画

将新单元格插入排序的 UITableView 的有效方法?