-->

NSFetchedResultsChangeUpdate fired instead of NSFe

2020-08-21 03:09发布

问题:

I have a NSFetchedResultsController initiated in the following way:

NSEntityDescription *myEntity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:myEntity];
[fetchRequest setFetchBatchSize:10];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"wasDeleted == %@", [NSNumber numberWithBool:NO]]];

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)];

[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor, nil]];

myFetchedResults = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
myFetchedResults.delegate = self;
[myFetchedResults performFetch:nil];

Some facts:

  • wasDeleted is an NSNumber property (BOOL) of MyEntity

  • If I update this property to [NSNumber numberWithBool:YES] the NSFetchedResultsControllerDelegate calls didChangeObject but firing NSFetchedResultsChangeUpdate instead of NSFetchedResultsChangeDelete.

  • However, if I pop the view and init again the fetched results controller, the object is not there anymore, showing that [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"wasDeleted == %@", [NSNumber numberWithBool:NO]]]; works.

  • After this NSFetchedResultsChangeUpdate, when cellForRow is called, I print wasDeleted and it's set to YES.

What can be wrong here?

(In other words, NSFetchedResultsChangeDelete can be called if the object still exists on the context however doesn't fit the predicate?)

回答1:

Of course changeUpdate and not changeDelete. You only updated a value and not deleted the whole item. If you delete the item from your db then it will call changeDelete. And it is not shown after the new init because you table is filtering based on this attribute.

You will need to listen for NSFetchedResultsChangeUpdate and check there if the attribute wasDeleted is changed. If so update your table view to your needs, eg. delete the specific row.



回答2:

I do the same thing in my app and have noticed that the -controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:newIndexPath delegate first gets called with a change type of NSFetchedResultsChangeDelete followed by a second call with a change type of NSFetchedResultsChangeUpdate.

The NSFetchedResultsChangeUpdate might be expected behaviour, but what's left unexplained is why the first call with NSFetchedResultsChangeDelete is missing. Can you confirm you're handling this case correctly?



回答3:

I had the exact same issue as you.

Do not use wasDeleted as your property name. You should not use variations of deleted when dealing with your CoreData objects.

I renamed my property to hidden, and used that for the predicate. Everything worked as you would expect.