Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Realm Collection Change notifications in production

Tags:

ios

swift

realm

From the docs, I'm using something similar to dynamically update a table view based on model changes:

let results = realm.objects(Message).filter("someQuery == 'something'").sorted("timeStamp", ascending: true)

// Observe Results Notifications
notificationToken = results.addNotificationBlock { [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()
    break
  case .Update(_, let deletions, let insertions, let modifications):
    // Query results have changed, so apply them to the UITableView
    tableView.beginUpdates()
    tableView.insertRowsAtIndexPaths(insertions.map { NSIndexPath(forRow: $0, inSection: 0) },
      withRowAnimation: .Automatic)
    tableView.deleteRowsAtIndexPaths(deletions.map { NSIndexPath(forRow: $0, inSection: 0) },
      withRowAnimation: .Automatic)
    tableView.reloadRowsAtIndexPaths(modifications.map { NSIndexPath(forRow: $0, inSection: 0) },
      withRowAnimation: .Automatic)
    tableView.endUpdates()
    break
  case .Error(let error):
    // An error occurred while opening the Realm file on the background worker thread
    fatalError("\(error)")
    break
  }
}

The docs don't actual detail how the table's data source delegates get this changed data so I figured a property with a custom getter would do:

var rows: Results<Message> {
    let realm = try! Realm()
    return result = realm.objects(Message).filter("someQuery == 'something'").sorted("timeStamp", ascending: true)
}

This works well in practice but the comment Results are now populated and can be accessed without blocking the UI made me question this approach. Should my getter return an empty array until the .Initial notification has fired within the notification block to ensure the main thread is never blocked?

like image 393
Ryan Brodie Avatar asked Oct 31 '22 03:10

Ryan Brodie


1 Answers

It's probably not obvious from the change notifications section of the docs, but it's actually covered here in the docs.

Results objects are live, auto-updating objects. When their values are changed elsewhere in the app (or on a background thread), they will automatically update on the next iteration of the run loop with the new values (There are caveats. Results on background threads need to be explicitly updated).

The point of the change notifications is to merely tell you that a change has occurred, and the next time you access results, the new values will already be in there. This is so you can update the UI accordingly.

So, your extra code isn't necessary. Just make sure that when a change notification block is triggered, you're still referring to the same parent results object when you refresh the UI, and it should just work™. :)

like image 185
TiM Avatar answered Nov 15 '22 05:11

TiM