How to make KVO trigger after realm transaction is completed?

323 views Asked by At

I have the models which is Group and Thread which have relation like

Group 1-Many Thread

I have this code, which will be trigger when leave group happens

[RLMRealm transactionWithBlock:^(RLMRealm *realm) {
    // Clear all unread in threads
    RLMResults<Thread *> *threads = [Thread allThreadsInGroupID:self._id];
    for (Thread *thread in threads) {
        [thread clearLocalUnreads]; // <-- Trigger KVO for thread
    }

    // Delete group
    [realm deleteObject:self];
} error:nil];

In the ViewController, I use KVO to observe some property of Thread and call this method when something changed

- (void)threadsControllerDidReloadData:(ThreadsController *)controller {

    // To prevent realm notification infinite loop in WorkspaceKPIDatasource
    if ([self.tableView.dataSource isKindOfClass:[WorkspaceTableViewController class]]) {
        WorkspaceTableViewController *workspaceTVC = (WorkspaceTableViewController *)self.tableView.dataSource;
        if ([workspaceTVC.contentDatasource isKindOfClass:[WorkspaceThreadsDatasource class]]) {
            [self.tableView reloadData];

            // Fix crash when reloadData is try to access group during leave since calling reloadData, the update
            // will not happen immediately. This line will force the layout to update immediately result in calling
            // - cellForRowAtIndexPath in the same run loop to prevent accessing invalidate group
            [self.tableView.superview layoutIfNeeded]; // <-- This solve crash
        }
        [workspaceTVC refreshHeader];
    }
}

There are two problems here

  1. KVO is trigger without realm transaction complete
  2. cellForRowAtIndexPath after calling reloadData will not run immediately result in even though the KVO trigger before group removed, when the cells are layout it crash why trying to access invalidate group.

I overcome this problem by choosing option 2 for now since it is easiest. But I think the more reasonable way to do is let KVO trigger only after transaction is completed. In that case no matter what happen in the transaction will be grouped at the end.

Because of this problem which lead me to think that KVO for realm maybe will likely to cause some problem like if transaction is failed midway but somehow KVO is already trigger because of the change at object level.

But by reading the document here. It seems to me like the KVO will call when write transaction occur but I don't know why in my case when Thread is updated and - threadsControllerDidReloadData: is called why [group isInvalidated] still return NO in that method

1

There are 1 answers

2
TiM On BEST ANSWER

From the sound of it, KVO might not be appropriate for what you're trying to accomplish.

If you're interacting with data in a table view, it might be more appropriate to use Realm's fine-grained notifications to register for changes. That system is designed to work with table views and will defer and deliver notifications at a time more appropriate for updating table view content.