背景
之前在做项目的时候,遇见过reloadData后找不到某个cell的问题,这里做个总结。
问题描述:
通过3D touch长按app图标,弹出新建脑图的选项,然后点击新建一张脑图。接下来的步骤如下:先进入app,在主界面创建一个新的思维导图;刷新collection view;最后打开这张思维导图(cell)进入编辑界面。但是每次reloadData之后,找到不到对应的cell,打开失败。
如下代码:
[self.collectionView reloadData];
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
[self performSegueWithIdentifier:openInFileIdentifier sender:cell];
Debug 调试发现获取的 cell 是 nil,在断点处查看 collection view 的 visibleCells 也是空的。猜测 reloadData 背后开启了分线程来处理这个事情,所以 reloadData 方法返回的时候,视图并没有完成刷新。
解决方案:
使用UICollectionView提供的如下方法处理:
- (void)performBatchUpdates:(void (NS_NOESCAPE ^ _Nullable)(void))updates completion:(void (^ _Nullable)(BOOL finished))completion; // allows multiple insert/delete/reload/move calls to be animated simultaneously. Nestable.
- 这个方法会在第一个 block 中处理 insert/delete/reload/move 等操作;
- 等操作完成之后再执行第二个block。
更新代码,问题解决。
[self.collectionView reloadData];
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
} completion:^(BOOL finished) {
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
[self performSegueWithIdentifier:openInFileIdentifier sender:cell];
}];
如果 cell 不在可视范围内呢?
如果 cell 刚好不在屏幕区域内,处于 visible 的状态,那么用上述方法依然会找不到 cell。
首先 collection view 滚动到目标 cell 处,然后在打开 cell。这里需要用到 scroll 的代理方法,以在滚动动画结束的时候,找到目标 cell。(滚动结束才能确定目标 cell 是 visible 的。)你还需要定义一个 indexPath 值以区分滚动结束的时候是否需要打开cell,以及要打开哪个 cell。
代码如下:
NSIndexPath *needOpenCellIndexPath;
- (void)reloadCollectionViewAndOpenCellWithIndexPath {
needOpenCellIndexPath = ...;
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadItemsAtIndexPaths:@[needOpenCellIndexPath]];
} completion:^(BOOL finished) {
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:needOpenCellIndexPath];
if (cell) {
[self performSegueWithIdentifier:LSLOpenMapSegueIdentifier sender:cell];
} else {
// Start scrolling to the target cell.
[self.collectionView selectItemAtIndexPath:needOpenCellIndexPath animated:YES scrollPosition:UICollectionViewScrollPositionTop];
}
}];
}
#pragma mark - <UIScrollViewDeleagte>
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
if (needOpenCellIndexPath) {
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:needOpenCellIndexPath];
[self performSegueWithIdentifier:openInFileIdentifier sender:cell];
}
needOpenCellIndexPath = nil;
}