I have a collection view and I am loading 20 cells in every call (Fetching) from firebase in it. So I have two sections where the first section is the count number of my source array and the second section is just showing the loading cell when a bool
value fetch more
is true.
This is the collection view code:
extension ProductViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return self.objectArray.count
} else if section == 1 {
return fetchingMore ? 1 : 0
}
return 0
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
cellHeights[indexPath] = cell.frame.size.height
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
var minimumLineSpacingForSectionAt: CGFloat
if section == 0 {
minimumLineSpacingForSectionAt = -50
} else {
minimumLineSpacingForSectionAt = 0
}
return minimumLineSpacingForSectionAt
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.section == 0 {
return CGSize(width: productCollectionView.bounds.width, height: CommonService.heightForRowAtIndexPathForiPhones(cellType: .itemCell))
} else {
return CGSize(width: productCollectionView.bounds.width, height: 70)
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ItemAlbumCollectionViewCell", for: indexPath) as! ItemAlbumCollectionViewCell
cell.setUpCell(product: objectArray[indexPath.row]!)
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "LoadingCollectionViewCell", for: indexPath) as! LoadingCollectionViewCell
cell.activityIndicator.startAnimating()
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let productCategoryViewController = Storyboards.ProductCategoryVC.controller as! ProductCategoryViewController
productCategoryViewController.products = objectArray[indexPath.row]!
pushViewController(T: productCategoryViewController)
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionView.elementKindSectionHeader:
guard let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "StreachyCollectionHeaderReusableView", for: indexPath) as? StreachyCollectionHeaderReusableView else { fatalError("Invalid view type") }
return headerView
default:
assert(false, "Invalid element type")
}
}
}
And this the function which is called for fetching data:
func pagination(forDivisionCollection: String) {
fetchProduct(forDivisionCollection: forDivisionCollection, completion: { newData in
self.productCollectionView.reloadSections(IndexSet(integer: 1))
self.objectArray.append(contentsOf: newData)
self.endReached = newData.count == 0
self.fetchingMore = false
UIView.performWithoutAnimation {
self.productCollectionView.reloadData()
}
})
}
And it is working perfectly.
Now I have added a top menu section with a couple of options.
If a user taps on that section the function func pagination(forDivisionCollection: String)
will be called with a parameter and it will filter data source with that parameter and populate data source according to the top menu option like this:
func pagination(isForNewDivision: Bool, forDivisionCollection: String) {
self.fetchingMore = true
if isForNewDivision == true {
self.objectArray.removeAll()
}
fetchProduct(forDivisionCollection: forDivisionCollection, completion: { newData in
self.productCollectionView.reloadSections(IndexSet(integer: 1))
self.objectArray.append(contentsOf: newData)
self.endReached = newData.count == 0
self.fetchingMore = false
UIView.performWithoutAnimation {
self.productCollectionView.reloadData()
}
})
}
But I am getting 'Invalid update: invalid number of items in section 0.
warning on Xcode when running it in the simulator and it is getting crashed on the physical device. I have researched a bit and come up with the solution of using performBatchUpdates
but none of them are working. So my question is in this kind of situation what would be the perfect way to fetch data and load in collection view? Thanks a lot in advance.