How to check for RLMResults invalidated?

1.2k Views Asked by At

When my user logs out, I clear my realm with realm.deleteAll(). After this, I get a lot of notifications resulting in reads from Results objects, which results in an exception realm::Results::InvalidatedException, "RLMResults has been invalidated". I can't find a way to

  • check a Results object for invalidation directly;

  • check a Results' realm object for invalidation; or

  • get the List the Results is derived from in order to check its invalidation state.

I can't think of anything else to look for. If there's a better way to clear the database that won't result in exceptions all over the place, I'd be happy to hear about that too.

Additional information: the exception is thrown even when calling count on a Results object, not just accessing its objects.

2

There are 2 best solutions below

2
Idan On

You can check if the first object exist, from Swift Docs:

public var first: T? { return rlmResults.firstObject() as! T? }

Returns the first object in the results, or nil if empty.

From Realm Documentation for Java (could not find the same wording in Swift Docs):

Notice that a RealmResults is never null not even in the case where it contains no objects. You should always use the size() method to check if a RealmResults is empty or not.

Long story short, check if the first object exist of or try to count the elements.

Sources:

Java - Class RealmResults,

Swift - Results Class Reference

EDIT: Here is a code sample, it is taken from Realm example and modified to my needs, they use notification token to detect if the array is empty

class Record: Object {
  dynamic var workoutName  = ""
  dynamic var totalTime    = ""
  dynamic var date         = ""
}
  let realm = try! Realm()
  let array = try! Realm().objects(Record).sorted("date")

  var notificationToken: NotificationToken?

  override func viewDidLoad() {
    super.viewDidLoad()

    setupUI()

    // Set results notification block

    notificationToken = array.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
      }
    }
  }

I also clear the table using deleteAll():

  func clearTable() {
    try! realm.write {
      realm.deleteAll()
    }
  }
0
Joel Kraut On

Results now has an invalidated property, as of 1.0.3.

Source: https://github.com/realm/realm-cocoa/blob/v0.103.0/CHANGELOG.md