我可能做了一件非常愚蠢的事,但我无法弄清楚我的生活是怎样的......
我试图做的很简单。我有UICollectionView
依赖于从服务器加载的数据。从服务器获取并设置数据后,我在集合视图上调用reloadData()
。当我执行此操作时,会使用正确的计数调用numberOfItemsInSection
,但cellForItemAt
永远不会被调用,除非我再次调用reloadData()
(甚至不需要延迟)。
这是一般性的想法(虽然我意识到它可能与其他地方的某些竞争有关,但也许这足以启动对话):
class MyViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
@IBOutlet weak var collectionView: UICollectionView!
var data = [DataModel]()
override func viewDidLoad() {
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UINib(nibName: "MyCell", bundle: nil), forCellWithReuseIdentifier: "MyCell")
getData()
}
func getData() {
someAsyncMethodToGetData() { (data) in
// Using CloudKit so I think this is necessary, but tried it with and without
DispatchQueue.main.async {
self.data = data
self.collectionView.reloadData()
// This is the only way to get cells to render and for cellForItemAt to be called after data is loaded
self.collectionView.reloadData()
}
}
// Gets called initially AND after reloadData is called in the data completion closure. First time is 0, next time is number of DataModel objects
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
// Only gets called initially (unless I call reloadData() twice)
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = feedCollectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as? MyCell else {
return UICollectionViewCell()
}
// Configure the cell with data...
return cell
}
}
所以这里有一些我已经尝试过的事情:
reloadData()
(添加符号断点并调用Thread.isMainThread
进行验证)reloadData()
移至按钮操作以消除任何线程问题的可能性 - 仍然必须单击按钮两次才能显示单元格performBatchUpdates
setNeedsLayout
和setNeedsDisplay
(不知道为什么在这种情况下需要这样做,但我确实是出于绝望而尝试。有什么建议吗?
好的,我想我发现了这个问题,但我想了解最好的解决方法。通过调用reloadData
显示,集合视图将仅重新加载已经可见的单元格。我在上面修改了一些代码,在调用getData()
之前返回1个单元格。当getData()
然后调用reloadData()
时,1个单元格会更新(但如果数据数组中有10个项目,它仍然只会[重新]显示1个单元格)。我认为这是有道理的,因为reloadData()
仅重新加载可见单元格,但当数组的长度发生变化并且屏幕上仍有空间显示时,这必然是一个常见问题。另外,为什么调用reloadData()
两次解决问题并显示从未见过的单元格?
Here是我上面代码的更简单版本,从服务器中删除整个"获取数据"想法并以简单的延迟取代。
答案 0 :(得分:10)
事情是在更改项目数后,UICollectionViewFlowLayout未正确无效。所以collectionView.contentSize
仍旧。你需要做一些像
self.collectionView.reloadData()
self.collectionView.collectionViewLayout.invalidateLayout()
这将告诉布局重新计算新数据源。
答案 1 :(得分:1)
首先请确保委托和数据源是否正确添加到collectionView。
第二次确认数据是填充断点还是简单打印
第三添加:
DispatchQueque.main.async{
self.collection.reloadData()
self.collection.collectionViewLayout.invalidateLayout()
}