Last active
April 10, 2017 18:09
-
-
Save alinebee/f37b343671e859aea93b6abcbaf7f126 to your computer and use it in GitHub Desktop.
UICollectionView performBatchUpdates crash demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: 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