UICollectionView performBatchUpdates:如果视图需要布局,则意外断言?

Mat*_*son 5 objective-c ios uicollectionview

如果我-[UICollectionView performBatchUpdates:]从内部viewWillAppear:,内部viewDidAppear:,这些方法之间调用,或者任何时候集合视图尚未由更大的UIView视图层次结构布局,则集合视图将断言:

***由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'无效更新:无效的节数.更新后的集合视图中包含的节数(X)必须等于更新前的集合视图中包含的节数(X),加上或减去插入或删除的节数(插入X,0删除)."

"X"是我插入的任何数量的项目.我已经确认数据源正在正确更新,并且更新中的索引路径是正确的.

当数据源刚刚在调用之前更新时,集合视图状态如何与数据源保持一致performBatchUpdates:?似乎出乎意料地触发了reloadData.

Mat*_*son 10

UICollectionView似乎有特殊行为(一个错误?):如果它需要布局,那么在调用更新块之前performBatchUpdates:有效地充当一个reloadData更新块,这会在更新块期间呈现您计划进行的任何更改,这对集合视图簿记有害.

如果您计划在视图正确布局之前将批量更新应用于视图(例如,从快速变化的数据模型环境中的通知处理程序),则需要确保在viewWillAppear:layoutIfNeeded视图中调用集合视图.这将阻止集合视图在调用中重新加载performBatchUpdates:.

我们通过在我们的集合视图数据源numberOfSections方法中放入一个日志并打印出这个回溯以查看它的调用位置来发现这种行为:

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
...
Run Code Online (Sandbox Code Playgroud)

在这里,您可以清楚地看到,在应用更新之前,调用将performBatchUpdates:访问数据源并与更改的模型保持一致.当然后调用块本身时,集合视图将抛出一个断言,就像我在原始问题中所显示的那样.

tl; dr - 当UICollectionView需要布局时,performBatchUpdates:有效地充当对调用reloadData的批处理更新块并因为不良的簿记而断言.通话layoutIfNeededviewWillAppear:,以避免这种行为.

  • 这个疯狂的错误只花了一天多的时间来解决.谢谢你的回答,指出了正确的方向.在`viewWillAppear`中执行`layoutIfNeeded`对我们不起作用,因为更新甚至更早开始 - 但在我们的数据模型更新解决它之前做了'layoutIfNeeded`!这绝对应该作为一个错误提交给Apple.如果他们决定执行`reloadData`而不是批量更新,他们必须丢弃批量更新块以避免不一致. (3认同)