【问题标题】:RealmSwift RealmCollectionChange tableView crashRealmSwift RealmCollectionChange tableView 崩溃
【发布时间】:2019-02-21 10:00:15
【问题描述】:

嘿,我正在尝试将 RealmNotifications 与更新 tableView 结合起来,但由于某种原因,由于存在的部分数量与领域通知发送的内容不一致,这会在 tableView 上不断产生多个崩溃。这是我用于观察Results<T> 上的任何更改的代码:

do {
            let realm = try Realm()
            sections = realm.objects(AssetSections.self).filter("isEnabled = true AND (assets.@count > 0 OR isLoading = true OR banners.@count > 0 OR tag == 'My Tools')").sorted(byKeyPath: "sort_order", ascending: true)

            guard let sections = sections else { return }

            // Watch on the asset sections
            notificationToken = sections.observe { [weak self] (change: RealmCollectionChange) in
                switch change {
                case .initial: break
                case .error(let error):
                    self?.handle(error: error)

                case .update(_, let deletions, let insertions, let modifications):
                    self?.updatedModel.onNext((insertions: insertions, modifications: modifications, deletions: deletions))
                }
            }
        } catch { }

上述代码发生在 ViewModel 上,而 ViewController 正在观察这些变化,如下所示:

vm.updatedModel
            .subscribe(onNext: { [weak self] (insertions, modifications, deletions) in
                guard let `self` = self else { return }

                self.tableView.beginUpdates()
                self.tableView.insertSections(insertions, animationStyle: .none)
                self.tableView.deleteSections(deletions, animationStyle: .none)
                self.tableView.reloadSections(modifications, animationStyle: .none)
                self.tableView.endUpdates()
            })
            .disposed(by: disposeBag)

我正在使用部分而不是行,因为这是一个包含多个部分且每个部分只有一行的 tableView。

我遇到的崩溃是,如果我执行拉动刷新,它会执行多个网络调用,从而对对象进行多次更改。有趣的是,如果我在拉动刷新期间快速向下滚动,我几乎总是可以复制崩溃。错误如下:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete section 14, but there are only 14 sections before the update'

我获取 tableView 的numberOfSections 的方式如下:

var numberOfSections: Int {
        return sections?.count ?? 0
    }

我的怀疑是,由于通知是在主线程的下一个 runLoop 上传递的,而且当我收到通知并且 tableView 对它做出反应时,我正在通过滚动和弄乱 UI 来使线程忙碌,它已经不同步了。但我不确定这是问题所在还是如何解决。

谢谢

编辑

避免这种情况的一种方法是在tableView 上使用.reloadData(),但它在大型数据集上特别受欢迎,而且我不能使用默认的tableView 动画。为了减少多次调用.reloadData() 对性能的影响,我使用debounce

vm.updatedModel
            .debounce(1.0, scheduler: MainScheduler.instance)
            .subscribe(onNext: { [weak self] (insertions, modifications, deletions) in
                guard let `self` = self else { return }

                self.tableView.reloadData()
            })
            .disposed(by: disposeBag)

【问题讨论】:

    标签: swift uitableview realm


    【解决方案1】:

    很好的问题,看起来 Realm 文档与您所做的完全一样(使用行而不是部分),但没有解决这个问题。我看不到一个明显的答案,但我能做的最好的就是这些可能的解决方法(虽然这两个都不是很好)。

    1. 重新编写更新代码以汇总结果,然后在完成后进行一次提交。
    2. 制作sections 的静态副本以在本地使用,并在订阅中更新它。即将 RealmCollection 复制到一个数组中,这不是该领域的动态视图。这将与您的更新保持同步。

    尽我所能。否则,我看不出你如何保证动态查询和通知之间的同步。

    【讨论】:

    • 谢谢 ces :) 这些是可能的解决方法。我做的另一件事是使用debounce 来减少tableView 所做的更新次数,而现在我正在做reloadData,它在性能方面并不是很好,除了它的工作之外我无法制作任何动画。
    • 是的,我可以看到 reloadData 可以工作,但必须对重复通知产生重大影响。如果您找到我想知道的解决方案,请务必添加答案。
    猜你喜欢
    • 1970-01-01
    • 2022-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多