UICollectionView seems to have a special behavior (bug?): If it needs a layout, then performBatchUpdates: effectively acts as reloadData before calling the update block, which displays all the changes that you plan to make during the update block poisonous to bookkeeping collection.
If you plan to have batch updates applied to the view before it is properly built (for example, from a notification handler in a rapidly changing data model environment), you need to make sure that in viewWillAppear: which you call layoutIfNeeded in the collection view. This will prevent reloading the collection view when calling performBatchUpdates:
We discovered this behavior by placing the log in our data source numberOfSections data source and printing this back trace to see where it was called from:
2014-11-12 15:30:06.173 CVCrasher[66830:6387719] [CV] #sections stack: ( 0 CVCrasher 0x000000010ba9122d -[MyViewController numberOfSectionsInCollectionView:] + 61 1 UIKit 0x000000010cfc2811 -[UICollectionViewData _updateItemCounts] + 147 2 UIKit 0x000000010cfc4a89 -[UICollectionViewData numberOfSections] + 22 3 UIKit 0x000000010cfaebae -[UICollectionViewFlowLayout _getSizingInfos] + 348 4 UIKit 0x000000010cfafca9 -[UICollectionViewFlowLayout _fetchItemsInfoForRect:] + 526 5 UIKit 0x000000010cfab51f -[UICollectionViewFlowLayout prepareLayout] + 257 6 UIKit 0x000000010cfc2a10 -[UICollectionViewData _prepareToLoadData] + 67 7 UIKit 0x000000010cfc30e9 -[UICollectionViewData validateLayoutInRect:] + 54 8 UIKit 0x000000010cf8b7b8 -[UICollectionView layoutSubviews] + 170 9 UIKit 0x000000010c9d1973 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 521 10 QuartzCore 0x0000000110cf2de8 -[CALayer layoutSublayers] + 150 11 QuartzCore 0x0000000110ce7a0e _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380 12 UIKit 0x000000010c9c5847 -[UIView(Hierarchy) layoutBelowIfNeeded] + 611 13 UIKit 0x000000010cf9c7b7 -[UICollectionView performBatchUpdates:completion:] + 164 ...
Here you can clearly see that the call to performBatchUpdates: hits the data source and becomes compatible with the modified model before the updates are applied. When the block itself is called, the collection view will invoke the statement, as shown in the original question.
tl; dr . When a UICollectionView needs a layout, performBatchUpdates: effectively acts as a reloadData call and will make the batch update block an assertion due to poor accounting. Call layoutIfNeeded in viewWillAppear: to avoid this.
source share