I'm working on a tvOS app using the new UICollectionViewDiffableDataSource to display up to 4 sections of groups of movies. If I'm scrolling the collectionView one poster at a time it works fine, but if I perform a quick swipe up or down between the sections, when we reach the top or bottom most cell a duplicate cell is made and 2 cells display in the same space overlapping each other. Here is the code I'm using to create the cells:
if let collectionView = self.collectionView
{
self.dataSource = UICollectionViewDiffableDataSource.init(collectionView: collectionView, cellProvider: { (collectionView, indexPath, entity) -> UICollectionViewCell? in
if let cell: PosterCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellIdentifier, for: indexPath) as? PosterCollectionViewCell
{
print("Creating cell \(cell) for content named \(entity.title ?? "") index path \(indexPath) on Thread \(String(describing: Thread.current))")
cell.populate(withEntity: entity)
return cell
}
return UICollectionViewCell()
})
}
Here are a few screen shots of what it looks like visually when the duplicate cells are created:
I noticed on the print logs, whenever I scroll through the collectionView and the cell goes offscreen and gets recreated - it resuses the cell previously created each time (7 times in this case) EXCEPT when I perform the quick swipe. In that case, the same cell gets dequeued and then another immediately gets created with a new memory address. I assumed the closure on the UICollectionViewDiffableDataSource init method was being called on the main thread, but did a printout of the thread the cells were being created on just incase (and they obviously were), so I'm not sure why even if a new cell was being created it would duplicate the cell and overlay it instead of replacing it.
Creating cell PosterCollectionViewCell: 0x7fbc94011220; baseClass = UICollectionViewCell; frame = (10 1237; 248.5 330); opaque = NO; layer = CALayer: 0x600003d7cfe0 for content named Joker index path [3, 0] on Thread NSThread: 0x6000028ccbc0{number = 1, name = main}
Creating cell PosterCollectionViewCell: 0x7fbc91e1d7d0; baseClass = UICollectionViewCell; frame = (10 1218; 248.5 330); opaque = NO; layer = CALayer: 0x600003d95b20 for content named Joker index path [3, 0] on Thread NSThread: 0x6000028ccbc0{number = 1, name = main}
This only happens when I perform the quick swipe and land on a poster that is the top or bottom most on a section I can navigate to. It won't stop at just 2 either. If I continue the behavior, yet another cell gets created, you can see here in the view debugger we have 3 cells for the Joker movie in a section that should just be displaying the one cell:
Also, note that I am using the new UICollectionViewCompositionalLayout and am setting it up with this method
static func createLayout(posterHeight height: CGFloat, postersOnScreen numPosters: CGFloat, headerHeight: CGFloat = 0, edgeInsets: NSDirectionalEdgeInsets? = nil) -> UICollectionViewCompositionalLayout
{
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0 / numPosters),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(height))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous
if let edgeInsets = edgeInsets
{
section.contentInsets = edgeInsets
}
if headerHeight > 0
{
let headerFooterSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(headerHeight))
let sectionHeader = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: headerFooterSize,
elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)
section.boundarySupplementaryItems = [sectionHeader]
}
return UICollectionViewCompositionalLayout(section: section)
}
The cell duplication also seems to only happen when scrolling to a cell that was previously offscreen. When the cell comes on screen it performs the standard animation when it becomes focused and the duplicate is created.