ObjectMonitor without dependency on NSFetchedResultsController #89

Closed
opened 2025-12-29 15:24:14 +01:00 by adam · 3 comments
Owner

Originally created by @colinmorelli on GitHub (Oct 1, 2016).

There may be some nuances that I'm missing here, but as far as I can tell, implementing ObjectMonitor without a dependency on NSFetchedResultsController should be fairly straightforward. Primarily, it would consist of subscribing to NSManagedObjectContextDidSaveNotification on the desired context, and observing the inserted/updated/deleted objects to see if any of them match the condition self.objectID == providedObject.objectID

There are a few benefits I see here:

  1. Almost certainly more performant. There's no overhead needed to track sections, ordering, etc when using this method that NSFetchedResultsController almost certainly contains
  2. Support for macOS < 10.12
  3. This is most important for me (and the reason I'm asking for this): the ability to avoid an initial fetch for the object (elaborated below)

Consider a case with a UITableView backed by an NSFetchedResultsController, where each row represents entity A that has a relation to another entity, B. Due to "limitations" in NSFetchedResultsController, there's no direct way to update a cell when the B entity for one of the records changes, without forcing a change to the A record that can be observed by the FRC. To get around this, it's possible to use an ObjectMonitor in each of the cells, that monitors the B entity for changes. The issue here is that every invocation of cellForRowAtIndexPath (to build a cell in the table) will then have to execute another query to fetch the current value of B, which is actually already known, just to be notified of future changes. Effectively, this translates a single query (select * from a join b) into an N+1 (even if, internally, Core Data can optimize a lot of this away to a cache lookup, it has to pay the cost of predicate parsing and setting up all of its internal structures to figure that out).

By breaking out of the FRC (for ObjectMonitor only), this case could be vastly improved. Ask the DataStack for an objectMonitor for an existing entity, for which you pay only the cost of constructing an object an adding an observer (both of which are "free", relative to the cost of setting up an FRC and performing the initial fetch). From that point forward, it simply notifies the application whenever the given entity changes by observing notifications.

If it's something you'd consider adding I may be able to attempt to work on a PR for it.

Originally created by @colinmorelli on GitHub (Oct 1, 2016). There may be some nuances that I'm missing here, but as far as I can tell, implementing `ObjectMonitor` without a dependency on `NSFetchedResultsController` should be fairly straightforward. Primarily, it would consist of subscribing to `NSManagedObjectContextDidSaveNotification` on the desired context, and observing the inserted/updated/deleted objects to see if any of them match the condition `self.objectID == providedObject.objectID` There are a few benefits I see here: 1. Almost certainly more performant. There's no overhead needed to track sections, ordering, etc when using this method that `NSFetchedResultsController` almost certainly contains 2. Support for macOS < 10.12 3. This is most important for me (and the reason I'm asking for this): the ability to avoid an initial fetch for the object (elaborated below) Consider a case with a UITableView backed by an `NSFetchedResultsController`, where each row represents entity A that has a relation to another entity, B. Due to "limitations" in `NSFetchedResultsController`, there's no direct way to update a cell when the B entity for one of the records changes, without forcing a change to the A record that can be observed by the FRC. To get around this, it's possible to use an `ObjectMonitor` in each of the cells, that monitors the B entity for changes. The issue here is that every invocation of `cellForRowAtIndexPath` (to build a cell in the table) will then have to execute another query to fetch the current value of B, which is actually already known, just to be notified of future changes. Effectively, this translates a single query (select \* from a join b) into an N+1 (even if, internally, Core Data can optimize a lot of this away to a cache lookup, it has to pay the cost of predicate parsing and setting up all of its internal structures to figure that out). By breaking out of the FRC (for ObjectMonitor only), this case could be vastly improved. Ask the DataStack for an objectMonitor for an existing entity, for which you pay only the cost of constructing an object an adding an observer (both of which are "free", relative to the cost of setting up an FRC and performing the initial fetch). From that point forward, it simply notifies the application whenever the given entity changes by observing notifications. If it's something you'd consider adding I may be able to attempt to work on a PR for it.
adam added the enhancementpending labels 2025-12-29 15:24:14 +01:00
adam closed this issue 2025-12-29 15:24:14 +01:00
Author
Owner

@JohnEstropia commented on GitHub (Oct 3, 2016):

I have considered this myself, just didn't find too much of a need of it (for now). If this was to be implemented however, I'm thinking KVO would be way more performant than handling NSManagedObjectContextDidSaveNotification directly.

Due to "limitations" in NSFetchedResultsController, there's no direct way to update a cell when the B entity for one of the records changes, without forcing a change to the A record that can be observed by the FRC. To get around this, it's possible to use an ObjectMonitor in each of the cells, that monitors the B entity for changes.

Have you tried implementing keysPathsForValuesAffectingValueForKey() on your relationship entity? Doing so might let NSFetchedResultsController get notified of relationship changes.

@JohnEstropia commented on GitHub (Oct 3, 2016): I have considered this myself, just didn't find too much of a need of it (for now). If this was to be implemented however, I'm thinking KVO would be way more performant than handling `NSManagedObjectContextDidSaveNotification` directly. > Due to "limitations" in NSFetchedResultsController, there's no direct way to update a cell when the B entity for one of the records changes, without forcing a change to the A record that can be observed by the FRC. To get around this, it's possible to use an ObjectMonitor in each of the cells, that monitors the B entity for changes. Have you tried implementing `keysPathsForValuesAffectingValueForKey()` on your relationship entity? Doing so _might_ let NSFetchedResultsController get notified of relationship changes.
Author
Owner

@ruslanskorb commented on GitHub (Mar 24, 2017):

I have tried implementing keysPathsForValuesAffectingValueForKey() on relationship entity, but it does not work. NSFetchedResultsController does not get notified of relationship changes.

@ruslanskorb commented on GitHub (Mar 24, 2017): I have tried implementing `keysPathsForValuesAffectingValueForKey()` on relationship entity, but it does not work. `NSFetchedResultsController` does not get notified of relationship changes.
Author
Owner

@JohnEstropia commented on GitHub (Jan 8, 2020):

ObjectPublishers are now the go to types for this. Closing ticket

@JohnEstropia commented on GitHub (Jan 8, 2020): `ObjectPublisher`s are now the go to types for this. Closing ticket
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore#89