NLCoreData
NLCoreData copied to clipboard
deleteInContext:predicate: doesn't call controllerDidChangeContent:
I have a fetched results controller with the delegate correctly set. When I insert a new managed object, the controllerDidChangeContent:
method is called as expected. However, when I delete objects, this method is not called on iOS 5. It does work fine on iOS 6.
I am using this utility method for inserting and deleting objects:
+ (void)performChanges:(void(^)(NSManagedObjectContext *context))changesBlock withCompletion:(void(^)(BOOL success))completionBlock {
NSManagedObjectContext *context = [NSManagedObjectContext backgroundContext];
[context performBlock:^{
changesBlock(context);
BOOL success = [context saveNested];
if (completionBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(success);
});
}
}];
}
The success BOOL is always YES, the changes are saved to the database (looking at it with a SQLite browser). Everything works fine, it's just that controllerDidChangeContent:
isn't called.
If I save on the mainContext then controllerDidChangeContent:
will be called.
[MyObject deleteInContext:[NSManagedObjectContext mainContext] predicate:@"created < %@", [NSDate dateWithTimeIntervalSinceNow:-10]];
[[NSManagedObjectContext mainContext] saveNested];
However, if I try to do something with MyObject within controllerDidChangeContent:
then I'm not seeing the changes. It's like nothing was deleted.
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
NSInteger found = [MyObject countWithPredicate:nil];
NSLog(@"found: %i", found);
}
"found" should be 0 after I deleted the objects, but it isn't. Again, this only happens on iOS 5.
Implementation of parent-child contexts was much worse on iOS 5 than it is on iOS 6. I don't do much iOS 5 anymore myself, but I'm not surprised you're seeing issues. If it's a non-heavy operation, I would suggest using the workaround you've discovered. Otherwise, you might try a mainContext callback just to force an update.
My workaround doesn't really work. Even though controllerDidChangeContent:
is called, all database related code inside that method is using old data.
What do you mean with "you might try a mainContext callback just to force an update"?
So is NLCoreData not working correctly on iOS 5?
One workaround could be to make the changes in the main context (only doable if it's not too heavy). Another workaround you could try is saving in the background, and when done, have a callback that makes a small change to the same object to force an update with the frc. That might or might not work, depending on whether the issue is notifying the frc or actually propagating the changes to the parent context.
As for bugs: since the core data parent-child pattern isn't bug-free on iOS 5, neither is this lib. And since I tend not to work with iOS 5 that much anymore, I probably won't delve too deep into those issues either. I wish I could give you a more satisfying answer. (Though I should say, sometimes it works perfectly fine on iOS 5, so even the bugs aren't very stable.)
Actually it seems to be a problem with countWithPredicate:
. So I'm now using the mainContext to delete my items, and controllerDidChangeContent:
is called. Within that method, I get different results for these 2 lines:
NSLog(@"found: %i", [MyObject fetchWithPredicate:nil].count);
NSLog(@"found: %i", [MyObject countWithPredicate:nil]);
The first line is correctly showing 0 results, the second line is higher - it still includes the deleted objects. Some kind of caching going on?
There shouldn't be any differences with regards to caching, but perhaps with how the fetch request is configured. There are a couple of things that could make a difference. For instance, check includesPendingChanges and includesSubentities on the NSFetchRequest (you'd have to use countWithRequest instead of countWithPredicate).