主线程与Collectionview.reloadData()

3
我有一个情况,即代码更改其collectionView数据源,然后多次调用reloadData(),我认为这会导致应用程序崩溃,因为数据源变化非常快,因此我使用DispatchQueue.main.async包装了该(更改数据源,然后重新加载集合视图)代码片段,从而解决了崩溃问题。
所以问题是:这样做是否有意义并解决了竞态条件?我的理解是用DispatchQueue.main.async包装这段代码将在reloadData()函数完成之前不会再次执行此段代码,这对吗?
如果您对如何解决此问题有其他想法,那就太好了。 更新: 例如,如果我们在主线程上有以下代码:
self.collectionView.dataSource = self.dataSource
self.collectionView.reloadData()

当这段代码被快速连续调用两次时,数据源会在第一次重新加载过程中发生更改。

为了解决此问题,我将此代码片段包装在异步块中,以确保数据源在第一次重新加载完成之前不会更改。具体如下:

DispatchQueue.main.async {
       self.collectionView.dataSource = self.dataSource
       self.collectionView.reloadData()
}

这会确保在 reloadData() 完成之前,数据源不会发生变化吗?

1个回答

3

reloadData 应该始终在主线程上调用。如果你没有这样做,那就是导致崩溃的原因。

好的,现在让我们谈谈数据的更改和对 reloadData 的调用如何相互耦合。也许你有这样一种情况:

background queue:
=================
    <networking>
    update the data
    main queue:
    ===========
        reloadData

您仍然可能会遇到麻烦,因为虽然两个对主队列的调用不会重叠,但是两个对后台队列的调用有可能重叠,因为它可能是一个并发队列。因此,这就是您的竞争条件;数据更新和重新加载已解耦。请记住,在重新加载数据期间调用了多个数据源方法,因此它们都需要查看相同的数据,否则如果在调用之间数据发生更改,则确实会崩溃并出现某种不一致性问题。并且使用该架构,这是非常真实的可能性。
但是,如果后台队列是一个串行队列,并且如果从该串行队列到主队列的步骤,则至少这种重叠是不可能的。因此,这将是一个更安全的解决方案。
background queue:
=================
    <networking>
    single background *serial* queue:
    =================================
        update the data
        main queue:
        ===========
            reloadData

然而,我们仍处于“共享数据”的情况。危险依旧存在。没有任何措施可以防止数据与其他队列同时被访问。为了防止这种情况的发生,您需要在每次访问数据时编写代码,确保只在一个队列上进行访问。毕竟,您的数据结构可能本身就不是线程安全的!但我们已经知道数据源方法只会在主线程上看到数据,因为这就是reloadData的工作原理。因此,最简单的方法就是制定一个规则,即每次访问数据都在主队列上进行:

background queue:
=================
    <networking>
    main queue:
    ===========
        update the data
        reloadData

所以,总之,如果这就是你现在正在做的事情,那么这就是正确的事情要做。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接