Skip to content

Instantly share code, notes, and snippets.

@alinebee
Last active April 10, 2017 18:09
Show Gist options
  • Save alinebee/f37b343671e859aea93b6abcbaf7f126 to your computer and use it in GitHub Desktop.
Save alinebee/f37b343671e859aea93b6abcbaf7f126 to your computer and use it in GitHub Desktop.
UICollectionView performBatchUpdates crash demo
//: Playground - noun: a place where people can play
import UIKit
class MockDataSource: NSObject, UICollectionViewDataSource {
let collectionView: UICollectionView
var numItems: Int
init(numItems: Int, collectionViewFrameSize: CGSize) {
self.numItems = numItems
self.collectionView = UICollectionView(frame: CGRect(origin: .zero, size: collectionViewFrameSize),
collectionViewLayout: UICollectionViewFlowLayout())
super.init()
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
collectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numItems
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
}
}
let dataSource = MockDataSource(numItems: 6, collectionViewFrameSize: .zero)
// At this point, because the dataSource's collection view has a size of zero, it will
// not initially check its data source for the number of items or sections.
// **Setting a non-zero size will cause it to check its data source immediately,
// avoiding the crash bug.**
// This triggers the collection view to ask its data source for the initial number of items.
// **If this line is commented out, and the initialFrameSize is zero, the performBatchUpdates()
// call below will crash.**
dataSource.collectionView.layoutIfNeeded()
// Increase the item count...
dataSource.numItems += 1
// ...and tell the collection view about the items that were added.
dataSource.collectionView.performBatchUpdates({
dataSource.collectionView.insertItems(at: [IndexPath(item: 0, section: 0)])
})
// If the collection view has properly initialized, the batch update will succeed:
// The item count that the collection view stored during layoutIfNeeded() was 6,
// the batch update adds 1 row, and the count after the update will be 7 to match
// the number reported by collectionView(_:numberOfItemsInSection:).
// If the collection view *hadn't* retrieved the initial item count yet (e.g. because
// we gave it a non-zero size or caused layoutIfNeeded() to be called), then
// performBatchUpdates() will call collectionView(_:numberOfItemsInSection:) itself
// after the increment already happened: so the stored item count at the start of the
// batch update will be 7 instead of 6. As a result it will die with an
// NSInternalInconsistencyException.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment