如果 dataSource 计数可能发生变化,是不是可以同时使用 reloadItemsAtIndexPaths 和 reloadData?
Posted
技术标签:
【中文标题】如果 dataSource 计数可能发生变化,是不是可以同时使用 reloadItemsAtIndexPaths 和 reloadData?【英文标题】:Possible to use both reloadItemsAtIndexPaths and reloadData if dataSource count may change?如果 dataSource 计数可能发生变化,是否可以同时使用 reloadItemsAtIndexPaths 和 reloadData? 【发布时间】:2015-12-10 18:30:06 【问题描述】:我正在通过 Crashlytics 调查一个带有 UICollectionView
的崩溃错误,该错误通常采用以下形式:
致命异常:NSInternalInconsistencyException 无效更新: 第 0 节中的项目数无效。包含的项目数 更新后的现有部分 (25) 必须等于数字 更新前该部分中包含的项目 (27),加上或 减去从该部分插入或删除的项目数(1 已插入,1 已删除)并加上或减去移入的项目数 或移出该部分(0 移入,0 移出)。
我认为这是因为我有一个collectionView,它会定期使用来自服务器的数据刷新自身,并且来自服务器的数据可能比客户端UICollectionViewDataSource
中包含的项目更多或更少。
当我从服务器获取新数据时,我在我的集合视图上调用reloadData
。
但是,由于用户在网络下载完成之前与我的收藏视图进行了交互,我之前可能曾致电reloadItemsAtIndexPaths
。 reloadItemsAtIndexPaths
似乎至少在几百毫秒和许多处理器周期内都没有完成。因此,当数据源在 reloadItemsAtIndexPaths
的中间更新时,会发生此崩溃。
reloadItemsAtIndexPaths
是否有“直接”形式?或者,鉴于我的用例,我必须始终调用reloadData
,这似乎会立即更新所有内容,并在最后使UICollectionView
保持良好状态。
编辑
根据 TwoStraws 的建议,这是我所做的:
// Prevent data source from batch updating while we work
self.dataSource.locked = YES;
[self.collectionView performBatchUpdates:^
[self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
completion:^(BOOL finished)
self.dataSource.locked = NO;
];
然后在我的数据源类中,在收到服务器的结果后,我总是调用assignResults
:
- (void)assignResults:(NSMutableArray *)newResults
if (!self.locked)
self.results = newResults;
[self.delegate handleDataSourceUpdated:self];
else
self.pendingResults = newResults;
- (void)setLocked:(BOOL)locked
_locked = locked;
if (!locked && self.pendingResults)
[self assignResults:self.pendingResults];
self.pendingResults = nil;
如您所见,只有在数据源未锁定时才会分配结果;否则在UICollectionViewController
解锁数据源时分配它们。请注意,所有这些方法都发生在主线程上,因此我无需担心我的布尔属性 locked
的同步。
【问题讨论】:
【参考方案1】:我相信您知道,比赛条件总是很复杂的问题。如果我对您的理解正确,您正在修改集合视图的数据源,而它仍在尝试重新加载自身,这意味着解决方案是保留一个单独的数据存储,以原子方式复制到集合视图的数据源。
所以:
集合视图从数据源 A 读取。 网络写入数据源 B。 在您指定的位置,一举将 B 复制到 A 中。 让集合视图重新加载。这样,collection view 永远不必担心竞争条件——它总是从固定的数据集中读取它所关心的。
【讨论】:
我不清楚 UICollectionView 在这种方法中 reloadItemsAtIndexPaths 的整个持续时间内是否会继续“指向”数据源 A。我们知道 UICollectionView 是否应该/应该如何工作吗? 您可以通过在其performBatchUpdates()
方法上使用完成块来检测集合视图何时开始和完成其更新——AFAIK 仅应在加载确定完成时触发。如果您的情况非常复杂,您可能需要使用布尔属性来标记“我即将开始更新”和“我肯定完成了,可以安全复制了。”
谢谢@twostraws——正如您在上面的编辑中看到的那样,这就是我所做的。以上是关于如果 dataSource 计数可能发生变化,是不是可以同时使用 reloadItemsAtIndexPaths 和 reloadData?的主要内容,如果未能解决你的问题,请参考以下文章