代码之家  ›  专栏  ›  技术社区  ›  Adam

使用UICollectionView观察领域-比赛条件

  •  2
  • Adam  · 技术社区  · 8 年前

    我在用 Realm 作为一个缓存层,每当数据呈现给用户时,它都会首先从数据库中取出并显示给用户。随后,将发送一个服务器请求,以获取最新版本的数据,并将其与 领域 数据库,并在 UICollectionView .

    问题是,当缓存的数据从 领域 数据库和 UICollectionView 如果正在更新,则服务器的更新请求可能在 UICollectionView 加载了所有的单元格,从 Results 列表是一个实时的数据集合,可以修改。例如,如果在服务器端删除了一个项目,那么live collection将少保存一个项目,因此会导致越界异常。

    尽管如此,即使是官方提供的代码 领域 考虑到 results 可以在 UITableView 一行一行地问:

    class ViewController: UITableViewController {
        var notificationToken: NotificationToken? = nil
    
        override func viewDidLoad() {
            super.viewDidLoad()
            let realm = try! Realm()
            let results = realm.objects(Person.self).filter("age > 5")
    
            // Observe Results Notifications
            notificationToken = results.observe { [weak self] (changes: RealmCollectionChange) in
                guard let tableView = self?.tableView else { return }
                switch changes {
                case .initial:
                    // Results are now populated and can be accessed without blocking the UI
                    tableView.reloadData()
                case .update(_, let deletions, let insertions, let modifications):
                    // Query results have changed, so apply them to the UITableView
                    tableView.beginUpdates()
                    tableView.insertRows(at: insertions.map({ IndexPath(row: $0, section: 0) }),
                                         with: .automatic)
                    tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: 0)}),
                                         with: .automatic)
                    tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: 0) }),
                                         with: .automatic)
                    tableView.endUpdates()
                case .error(let error):
                    // An error occurred while opening the Realm file on the background worker thread
                    fatalError("\(error)")
                }
            }
        }
    
        deinit {
            notificationToken?.invalidate()
        }
    }
    

    我唯一能想到的解决方法是创建一个结果的深层副本,以及使用信号量或类似物来同步观察函数的主体,以确保数据不会进入不一致的状态,这是我认为非常低效的状态。(注意 tableView.endUpdates() 这并不意味着 UtableView 已重新加载所有数据,但它只是被分派到队列中,并准备以异步方式进行处理。)

    我想听听关于如何以有效的方式实施这一点的任何建议,以消除提到的种族条件。

    2 回复  |  直到 8 年前
        1
  •  1
  •   Josh Homann    8 年前

    您需要在主线程上执行所有UI更新。如果执行此操作,第一组结果将更新主线程上的集合视图,当下一组结果同时出现时,它将在主线程上排队,以便在第一组结果完成后更新。

        2
  •  0
  •   lesyk    8 年前

    基于:

    问题是,当从Realm数据库检索缓存数据并更新UICollectionView时,服务器的更新请求可能在UICollectionView加载所有单元格之前完成,并且由于结果列表是实时数据集合,因此可能已被修改。

    我不认为会发生这种情况,因为一旦您的live collection发生更改,就会触发更新通知,并相应地重建/更新collection。然而,正如我在PM中所说,那是一段时间以前我与realm合作的时候了。

    测试你的假设很容易:降低模拟器的网络速度,或者制作巨大的表格等等。我真的很好奇你是否真的能制造一个你认为你会遇到的问题。

    推荐文章