Realm-cocoa: NSInternalInconsistencyException with multi section tableViews

Created on 15 Dec 2017  Â·  4Comments  Â·  Source: realm/realm-cocoa

Goals

Back a multi-section tableview from several Results<T> sources, receiving updates from observe

Expected Results

Each section updates independently, changes to one data source don't apply before their observe block is called

Actual Results

Eventually an NSInternalInconsistencyException will be thrown on the tableview.

Steps to Reproduce

  1. Create a tableview with 2 sections
  2. Back each section with a Results<T>
  3. observe each data source
  4. Insert/modify lots of values (delete is probably a problem too, but there's none of that going on in our particular case)
  5. Crash

Code Sample

poc.zip

Version of Realm and Tooling

Realm framework version: 3.0.2

Realm Object Server version: n/a

Xcode version: 9.1

iOS/OSX version: Any (11 currently, but we've seen this crash in 10 as well)

Dependency manager + version: Cocoapods 1.3.1

O-Community T-Enhancement

Most helpful comment

I tried asking a detailed question on SO about this, but didn't get any decent responses. For reference:
https://stackoverflow.com/questions/47194597/when-are-realm-notifications-delivered-to-main-thread-after-writes-on-a-backgrou

All 4 comments

I tried asking a detailed question on SO about this, but didn't get any decent responses. For reference:
https://stackoverflow.com/questions/47194597/when-are-realm-notifications-delivered-to-main-thread-after-writes-on-a-backgrou

Wondering if anyone has found a solution for this, been keeping my eye on it for several months. It's seemingly impossible to have a realm-backed table with multiple sections in it.

If that's the case, it'd be great to get some official confirmation from the Realm team so we can redesign things accordingly to get past these intermittent crashes.

Hey All - We don't expose an easy way to do this today. Each Notification Block is attached to a particular Results set. In the future, we would like to improve this.

I've been developing a new iOS app for about 8 months, and gradually getting into more complex scenes and tableviews – eventually running into this problem just like a lot of folks using Realm.

So some observations, and a little workaround that MAY help depending on your circumstances ...

Observations

In my observation, this NSInternalInconsistencyException only seems to arise when my two-or-more Realm-backed sections have the possibility to be mutually affected by a single DB transaction. Most often I think this would mean: multiple Realm collections that use the same underlying model.

So for example, my scenario can be boiled down to something like:

- Section 0: Inspections – filtered to incomplete
- Section 1: Inspections – filtered to complete

You can see what happens here: when ONE inspection gets completed by the user, TWO separate notifications are issued. Because the record needs to move from section 0 to section 1, two separate tableView update blocks are called – and that's where we get into trouble.

Simple workaround

If your app can tolerate losing the smooth row-level animations of dropping cells from 1 section and inserting them into the other ... well you can avoid the crash by simply collapsing two separate subscriptions into one, ignoring Realm's fine-grained notifications, and forcing both sections to reload:

// Note: 'inspections' is the larger collection, underlying both sections

dataSource.inspections.observe { [weak self] _ in
  self?.tableView.reloadSections([0 , 1], with: .automatic)
}

This approach should be expanded to cover as many table sections as could be affected by a single write transaction, of course.

To my eyes, this is fairly brute-forcey, and is only a couple notches better than just running tableView.reloadData(). But the latter is something I've tried to avoid at all costs, since it's essentially the nuclear option.

For my particular app (B2B domain, low requirements for elegant UI animations), this is perfectly adequate for the couple of areas in which I've encountered the problem so far. With any luck maybe it will help somebody else out here.

EDIT: my workaround is a (much) dumber version of the DIY approach by Isaiah Turner, which looks nice.

Was this page helpful?
0 / 5 - 0 ratings