How to listen to saving or updating certain objects in CoreData

First of all, I tried to use the FetchedResultsController to solve my problem. This was an atypical use of FRC in that I did not update the TableView, I used it only to determine if entities were changing, so I knew when to save to the server:

self.fetchedResultsController = [Document MR_fetchAllSortedBy:@"timestamp" ascending:NO withPredicate:[NSPredicate predicateWithFormat:@"report.remoteId != nil && dirty == YES"] groupBy:nil delegate:self inContext:_managedObjectContext]; 

The problem is that FRC does not receive updates when the relationship object changes. IE, if report.remoteId goes from zero to non-nil, I will not see the update, since FRC only listens for changes to the Document object. The restriction is indicated here: http://www.mlsite.net/blog/?p=825 and here Changing the property of managed objects does not cause NSFetchedResultsController to update the table view

Not sure if I really want to implement a workaround, as I fell as if I were using FRC for things that he was not going to do. I don’t think the apple will fix this restriction, so I really don’t want to break the circular snap into a square hole to solve my problem.

A couple of options

Leave a notification in the code after I saved the objects, and then listen to it elsewhere. The only thing I don’t like about this is that the programmer needs it to do this and keep it in the know, i.e. If someone comes in and saves the object elsewhere, he must remember to trigger a notification.

OR

Listen to saving MOC by default. This is what I really would like to do. Something like that:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDataModelChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:[NSManagedObjectContext MR_defaultContext]]; - (void)handleDataModelChange:(NSNotification *)note { NSSet *updatedObjects = [[note userInfo] objectForKey:NSUpdatedObjectsKey]; NSSet *deletedObjects = [[note userInfo] objectForKey:NSDeletedObjectsKey]; NSSet *insertedObjects = [[note userInfo] objectForKey:NSInsertedObjectsKey]; // Do something in response to this } 

Here is my dilemma with this. This will listen for all changes in the MOC by default. I really only care about changes in a few entities. So yes, I can filter out the objects that excite me in every call. BUT, I have a case where I save a lot of other objects in which I do not care. This means that NSManagedObjectContextObjectsDidChangeNotification will fire a ton, and most of the time I don't care. I do not want to slow down my application by constantly receiving this notification and taking time to filter out all the objects that do not bother me.

Is there a way to listen to certain objects? Either in CoreData or in MagicalRecord?

If the answer is no, is there a good alternative for listening to changes to a specific entity (and its relationships)?

+5
source share
2 answers

There is no way to listen for changes for a specific set of objects; catch NSManagedObjectContextObjectsDidChangeNotification (either done or saved), and filtering is the right approach, with the caveat that observing a key value is also an option if you are talking about specific entity instances.

However, it is worth noting that NSManagedObjectID is thread safe and provides a getter for NSEntityDescription . So you can, for example,

 - (void)handleDataModelChange:(NSNotification *)note { NSSet *updatedObjects = [[note userInfo] objectForKey:NSUpdatedObjectsKey]; NSSet *deletedObjects = [[note userInfo] objectForKey:NSDeletedObjectsKey]; NSSet *insertedObjects = [[note userInfo] objectForKey:NSInsertedObjectsKey]; NSMutableArray *objectIDs = [NSMutableArray array]; [objectIDs addObjectsFromArray:[updatedObjects.allObjects valueForKey:@"objectID"]]; [objectIDs addObjectsFromArray:[deletedObjects.allObjects valueForKey:@"objectID"]]; [objectIDs addObjectsFromArray:[insertedObjects.allObjects valueForKey:@"objectID"]]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(){ NSSet *affectedEntities = [NSSet setWithArray:[objectIDs valueForKeyPath:@"entity.name"]]; if([affectedEntities containsObject:@"InterestingEntity"]) { // get back onto the main thread and do some proper work; // possibly having collated the relevant object IDs here // first — whatever is appropriate } }); } 
+9
source

After reading the documents and some other forms, I also suggested another possible solution.

Why not override the didSave method of the managed object to catch a change to this object.

 @implementation Report (helper) - (void) didSave { [super didSave]; // if not on default context no-op if ([NSManagedObjectContext MR_defaultContext] != self.managedObjectContext) return; // send custom notification here } @end 

Still dealing with sending a custom notification, but at least encapsulated in a managed entity, so developers don’t have to worry about where to send the notification.

On the plus side, this is only done for the managed entity that I care about.

The minus is that it is called for all contexts of managed objects. However, I do not think that checking the MOC will be a hard hit.

Not sure if this is better / worse than listening to the default MOC for saving and filtering. Plus, in this case, I know that I'm listening to what only this MOC saves. Despite the fact that I can filter in the background job, I still filter tons of data in this case, which I do not need to deal with.

Thoughts?

+2
source

Source: https://habr.com/ru/post/1210111/


All Articles