How to Use Realm.Addnotificationblock

How to use realm.addNotificationBlock?

You can check the class reference to implement the notification handler that catch the changes in the RLMRealm: http://realm.io/docs/cocoa/0.80.0/api/Classes/RLMRealm.html

In this issue you have a test case (non main thread) using the addNotificationBlock.

I hope this may help you.


UPDATE

Check also the examples: RealmTableViewExample

- (void)viewDidLoad
{
[super viewDidLoad];
[self setupUI];

// Set realm notification block
__weak typeof(self) weakSelf = self;
self.notification = [RLMRealm.defaultRealm addNotificationBlock:^(NSString *note, RLMRealm *realm) {
[weakSelf reloadData];
}];
[self reloadData];
}

- (void)reloadData
{
self.array = [[DemoObject allObjects] arraySortedByProperty:@"date" ascending:YES];
[self.tableView reloadData];
}

There is no method addNotificationBlock in Realm. Where is it?

3.0.0 Release notes (2017-10-16)

Breaking Changes

Old API New API

NotificationToken.stop() NotificationToken.invalidate()

-[RLMNotificationToken stop] -[RLMNotificationToken invalidate]

RealmCollection.addNotificationBlock(:) RealmCollection.observe(:)

Try observe?

How to use Realm notifications

Make notificationToken an ivar:

var notificationToken: NotificationToken?

deinit{
//In latest Realm versions you just need to use this one-liner
notificationToken?.stop()

/* Previously, it was needed to do this way
let realm = Realm()
if let notificationToken = notificationToken{
realm.removeNotification(notificationToken)
}
*/
}

override func viewDidLoad() {
super.viewDidLoad()
let realm = Realm()
notificationToken = realm.addNotificationBlock { [unowned self] note, realm in
self.tableView.reloadData()
}
...
}

Add Notification to Array of Realm Results

I would go like this, looping through the array as you suggested:

var objectsBySection = [Results<DemoObject>]()

// Fill the objectsBySection array like in your example
...

for (index, objects) in objectsBySection.enumerated() {
registerNotifications(for: objects, in: index)
}

where the registerNotifications(for:in:) method is defined like this:

func registerNotifications(for results: Results<DemoObject>, in section:Int) {

let notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
guard let tableView = self?.tableView else { return }

switch changes {
...
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: section) }), with: .automatic)
tableView.deleteRows(at: deletions.map({ IndexPath(row: $0, section: section)}), with: .automatic)
tableView.reloadRows(at: modifications.map({ IndexPath(row: $0, section: section) }), with: .automatic)
tableView.endUpdates()
break
...
}
}
notificationTokens.append(notificationToken)
}

We assume var notificationTokens is defined at the class level.

Now, you mentioned that new sections could be added at any time, so let's deal with that too. So we add the plain old non-fine grained notification block and we check if there are new sections added.

notificationToken = realm.addNotificationBlock { [unowned self] note, realm in
// Let's see what the section list looks like now
let sections = Set(realm.objects(DemoObject.self).value(forKey: "sectionTitle") as! [String])

if !Set(sectionTitles).isSuperset(of: sections) {
sectionTitles = Array(sections)

self.tableView.reloadData()
}
}

So, in my simplistic approach, it reloads everything only if new sections are added. If you want to benefit from the nice insert animations you could check instead what sections were added, insert them one by one in the table and then add the new objects to them.

Note: My method to check if sections were added is quite intensive, basically it iterates through all the objects in the DB, so you may want to check it with a realistic load in your app. Unfortunately, until Realm would permit distinct or group by queries this is the only way I could imagine to solve this issue.

Realm addNotificationBlock returning error

An untranslated std::exception is never supposed to make it out of Realm, so that part is a bug.

If you can consistently reproduce the issue, you can set an exception breakpoint in Xcode to break at the point where the error is actually occurring and hopefully find out what's wrong that way.

Testing code which uses Realm addNotificationBlock

You can use expectation(description:) and waitForExpectations(timeout:handler:) to test async methods as follows.

func test() {
let q = DispatchQueue(label: "Q")

q.async {
let realm = try! Realm()
try! realm.write {
realm.add(TestObj())
}
}

let e = expectation(description: "Notification fired")

let realm = try! Realm()
let token = realm.addNotificationBlock { (notification, realm) in
print("notification block")
e.fulfill()
}

waitForExpectations(timeout: 2.0, handler: nil)
token.stop()
}


Related Topics



Leave a reply



Submit