首页 > 解决方案 > 观察 Realm 结果集的变化

问题描述

我正在开发一个使用 Realm 数据库的 iOS 应用程序。在我的AppDelegate中,我定义了一个 Realm 结果集,如下所示:

var results: Results<RealmWidget>!
var notificationToken: NotificationToken? = nil

do {
    let realm = try Realm()
    if results == nil {
        results = realm.objects(RealmWidget.self)
    }
} catch {
    print(error.localizedDescription)
}

我观察到这个结果集的变化如下:

if notificationToken == nil {
    notificationToken = results.observe { (changes: RealmCollectionChange) in
        switch changes {
        case .update(_, _, let insertions, _):
            if insertions.count > 0 {
                // show badge on tab bar
                // play sound to get the user's attention
            }
        default:
            break
        }
    }
}

每当在数据库中插入新RealmWidget对象时(由于从服务器接收数据而发生),我想UITabBar在我的 UI 中显示一个徽章。此代码似乎工作正常。

在我的应用程序的另一部分,我有一个视图控制器,UITableView它用于显示所有RealmWidget对象(按时间戳排序)。在该视图控制器内部,我还有一个结果集,我观察它的变化,因此我知道何时重新加载 tableview。该代码如下所示:

var results: Results<RealmWidget>!
var notificationToken: NotificationToken? = nil

class MyViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

  override func viewDidLoad() {
      super.viewDidLoad()

      results = RealmHelper.getRealmWidgets() // helper method that  queries Realm for all of the Widget objects and sorts them by timestamp
      notificationToken = results.observe { [weak self] (changes: RealmCollectionChange) in
          DispatchQueue.main.async {
              self!.tableView.reloadData()
          }
      }
  }
}

这段代码似乎也能正常工作,直到我在AppDelegate. 然后我意识到,每当我从这个视图控制器中删除一行时UITableView,我也会听到声音播放。这是出乎意料的,因为我应该只在UITabBar插入而不是删除时将徽章添加到并播放声音。

我在我定义的观察块中添加了一些调试代码,AppDelegate所以它看起来像这样:

if notificationToken == nil {
    notificationToken = results.observe { (changes: RealmCollectionChange) in
        switch changes {
        case .update(_, let deletions, let insertions, let modifications):
            print("widget deletion count: \(deletions.count)")
            print("widget insertion count: \(insertions.count)")
            print("widget modification count: \(modifications.count)")
            if insertions.count > 0 {
                // show badge on tab bar
                // play sound to get the user's attention
            }
        default:
            break
        }
    }
}

当我运行应用程序时,使用 tableview 切换到视图控制器,然后删除其中一行(这会导致RealmWidget从数据库中删除相应的对象),我在调试控制台中看到以下输出:

widget deletion count: 2
widget insertion count: 1
widget modification count: 0

我不清楚这方面的一些事情:

如果有人可以解释这里发生的事情,我当然会感谢您的帮助!

- 编辑 -

我在视图控制器内部定义的观察块中添加了相同的调试代码,并注意到其他一些奇怪的东西。当这个“问题”发生时,我在调试控制台中看到这个输出:

widget deletion count (AppDelegate): 2
widget insertion count (AppDelegate): 1
widget modification count (AppDelegate): 0

widget deletion count (View controller): 1
widget insertion count (View controller): 0
widget modification count (View controller): 0

因此,我的视图控制器中的观察块显示 1 个删除,但我的 AppDelegate 中的观察块显示 2 个删除和 1 个插入!奇怪的是,这并不是 100% 发生的。如果我UITableView正在显示 10 个RealmWidget对象并且我一次删除一个对象,大约 75% 的时间,我会在控制台中看到上述输出。但另外 25% 的时间,输出正是我所期望看到的:

widget deletion count (AppDelegate): 1
widget insertion count (AppDelegate): 0
widget modification count (AppDelegate): 0

widget deletion count (View controller): 1
widget insertion count (View controller): 0
widget modification count (View controller): 0

两个观察块中的 1 个删除。我现在比以前更糊涂了!;-)

-- 编辑 #2 --

似乎这种行为与Results<RealmWidget>我的 AppDelegate 和Results<RealmWidget>我的视图控制器中的 没有以相同的方式对查询结果进行排序这一事实有关。

在我的AppDelegate,是领域中所有对象results的未排序集合。RealmWidget但是在我的视图控制器中,我用来定义的辅助方法是Realm 中所有对象results排序集合。RealmWidgets

标签: iosswiftrealm

解决方案


我通过 GitHub 将这个问题发布到 Realm 并得到以下回复:

是的,当对象被删除时,未排序的结果会重新排列。如果您不要求明确的排序顺序,那么对象只是按照它们碰巧存储在磁盘上的顺序列出,这是一个不稳定的顺序,当对象被删除时会发生变化。

我们目前报告最后的对象移动到已删除对象的位置,因为该对象也被删除然后插入新位置。

https://github.com/realm/realm-cocoa/issues/6130


推荐阅读