I try to figure out the improvement of apply(_:animatingDifferences:)
function call without animation in iOS 15 Simulator.
As log shown below, after removing an item and apply edited snapshot to diffable data source, it trigger several unnecessary calling to new cell that did not appear on screen.
ENV:
- MacBook Air (M1, 2020), macOS Big Sur 11.4 (20F71)
- Xcode Version 13.0 beta (13A5154h),
- iOS 15.0 Simulator
configure AlbumItemCell:(0x0000000128042400) at section:(0), item:(0)
configure AlbumItemCell:(0x0000000125624aa0) at section:(0), item:(1)
configure AlbumItemCell:(0x00000001280442a0) at section:(0), item:(2)
configure AlbumItemCell:(0x0000000128045670) at section:(0), item:(3)
configure AlbumItemCell:(0x0000000128050af0) at section:(0), item:(4)
configure AlbumItemCell:(0x0000000125626430) at section:(0), item:(5)
remove last items
configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(0)
configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(1)
configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(2)
configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(3)
configure AlbumItemCell:(0x000000012571f970) at section:(0), item:(4)
The definition of ITEM list below, could you see any problem here? @J0hn
class AlbumItem: Hashable {
let albumURL: URL
let albumTitle: String
let imageItems: [AlbumDetailItem]
init(albumURL: URL, imageItems: [AlbumDetailItem] = []) {
self.albumURL = albumURL
self.albumTitle = albumURL.lastPathComponent.displayNicely
self.imageItems = imageItems
}
func hash(into hasher: inout Hasher) {
hasher.combine(identifier)
}
static func == (lhs: AlbumItem, rhs: AlbumItem) -> Bool {
return lhs.identifier == rhs.identifier
}
private let identifier = UUID()
}
BTW, those unnecessary calling occurs in demo on session 10252,to reproduce this issue:
- add delegate for the collection view, disable prefetching to reduce logs:
private func configureHierarchy() {
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.backgroundColor = .systemBackground
// collectionView.prefetchDataSource = self
collectionView.isPrefetchingEnabled = false
collectionView.delegate = self
view.addSubview(collectionView)
}
2. implement the selection callback for removing item from snapshot:
extension PostGridViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("remove items at section:(\(indexPath.section)), item:(\(indexPath.item))")
var snapshot = dataSource.snapshot()
let identfiers = snapshot.itemIdentifiers(inSection: Section.ID.allCases[indexPath.section])
snapshot.deleteItems([identfiers[indexPath.item]])
dataSource.apply(snapshot, animatingDifferences: false)
}
}
- finally, remove reload stuff in cell registeration:
let cellRegistration = UICollectionView.CellRegistration<DestinationPostCell, DestinationPost.ID> { [weak self] cell, indexPath, postID in
guard let self = self else { return }
print("configure DestinationPostCell:(\(Unmanaged.passUnretained(cell).toOpaque())) at section:(\(indexPath.section)), item:(\(indexPath.item))")
let post = self.postsStore.fetchByID(postID)
let asset = self.assetsStore.fetchByID(post.assetID)
cell.configureFor(post, using: asset)
}
THEN I ran this demo and clicked the first item to remove it, similar log came out:
configure DestinationPostCell:(0x000000015ef11940) at section:(0), item:(0)
configure DestinationPostCell:(0x000000015ed20410) at section:(0), item:(1)
configure DestinationPostCell:(0x000000015ed21900) at section:(1), item:(0)
remove items at section:(0), item:(0)
configure DestinationPostCell:(0x000000015ed433c0) at section:(1), item:(2)
configure DestinationPostCell:(0x000000015ed433c0) at section:(0), item:(0)
configure DestinationPostCell:(0x000000015ed433c0) at section:(1), item:(0)
configure DestinationPostCell:(0x000000015ed433c0) at section:(1), item:(1)
configure DestinationPostCell:(0x000000015ef11940) at section:(1), item:(1)