Reputation: 27113
I have a question how can I listen to changes in my data model.
I have NSManagedObject email with property progress. So while app is sending email, I every time update property progress.
I want to listen to data model and if changed update my view.
I added:
for (SAPEmail *email in _emails)
{
[self addObserver:email forKeyPath:@"progress" options:NSKeyValueObservingOptionNew context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"progress"])
{
SAPEmail *email = object;
NSLog(@">>>>>>>>>>> progress: %@", email.progress);
}
}
But seems it does not work for me.
I also using MagicalRecord.
I also tried to observe context
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleDataModelChange:)
name:NSManagedObjectContextObjectsDidChangeNotification
object:myManagedObjectContext];
But when I debug my data model already was being update 10 times (because I update progress from 0 - 9), but handleDataModelChange invoked just once after all update where made. But I need to get all 10 update each time when data model updated to update progress view.
One more if I use this
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(managedObjectContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:nil];
and then for example try to refresh data:
- (void)managedObjectContextDidSave:(NSNotification *)notification
{
NSLog(@">>>>>>>>>+++++");
_emails = [SAPCoreDataEmailHelper emailsWithStatus:EmailStatusInProgress];
[_theTableView reloadData];
}
+ (NSArray *)emailsWithStatus:(EmailStatus)status
{
NSPredicate *prediacte = [NSPredicate predicateWithFormat:@"status == %d", status];
NSArray *emails = [SAPEmail MR_findAllWithPredicate:prediacte];
return emails;
}
I can see how works NSLog but then my app is freeze.
Upvotes: 0
Views: 510
Reputation: 69647
You're setting up the observer incorrectly, use the following code to set up your observations.
for (SAPEmail *email in _emails)
{
[email addObserver:self forKeyPath:@"progress" options:NSKeyValueObservingOptionNew context:NULL];
}
I also recommend setting the context parameter for KVO observations to be triggered properly.
Update
When you want to observe changes from Core Data, you have some options. I don't think you are grasping that there are multiple ways to do it. The first way is to watch for changes to a single property on a single object. This is the KVO approach. If you want to listen to save events for a particular context, then you'll need to use the NSNotificationCenter approach. You'll need to mix the two when you're making changes to multiple contexts. That is, if you're observing a property on an object in context A, and you make changes to that object/property in context B, you need to set up the NSNotificationCenter observation handler on NSManagedObjectContextDidSaveNotification to merge the new changes from context B into context A. From there, when the context merge is complete, then your KVO observation on property/object in context A is then triggered.
In your case, in your managedOjbectContextDidSave:
method, you need to call
-mergeChangesFromContextDidSaveNotification:
to merge your changes between contexts. I also recommend using multiple contexts, and not hold a single context in your SAPCoreDataEmailHelper class. When you get to multithreaded scenarios, you will encounter random crashes with a single context and multiple threads.
Upvotes: 0
Reputation: 80265
Even better, hold your fetched objects in a NSFetchedResultsController
. In this way you can automatically monitor very specific entities without going into too much detail for observing every attribute.
Have you controller implement the NSFetchedResultsControllerDelegate
methods. It is really simple, check out the Xcode templates using Core Data (e.g. Master-Detail Project, check "Core Data").
Upvotes: 1