如果 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

但是,由于用户在网络下载完成之前与我的收藏视图进行了交互,我之前可能曾致电reloadItemsAtIndexPathsreloadItemsAtIndexPaths 似乎至少在几百毫秒和许多处理器周期内都没有完成。因此,当数据源在 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?的主要内容,如果未能解决你的问题,请参考以下文章

如果底层表结构发生变化,我们是不是需要重新创建物化视图

如果数据发生变化,文档是不是会从 couchbase 视图中删除?

加入同一个表时 SQL 结果计数发生变化

算法小结

Python - 用反向计数器附加行号

Python - 用反向计数器附加行号