NSFetchedResultsCotroller
behaves strangely when using predicate. The following code prints the output:
Rows - 0
But when I comment out [self saveContext]
(the first one) the output becomes:
Rows - 1
Removing the predicate (query.predicate
) fixes things and the output is always:
Rows - 1
I suspect it has something to do with how NULL
is compared in memory vs in DB query. Any idea what is actually going on?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSError *error;
// Deletes persistent store coordinator behind the scene
// Create an empty entity with the optional fields attr1 (string) and attr2 (date)
Entity *e = [NSEntityDescription insertNewObjectForEntityForName:@"Entity" inManagedObjectContext:[self managedObjectContext]];
[self saveContext]; // <---------------- Code to comment out
// Setup fetched results controller
NSPredicate *pred = [NSPredicate predicateWithFormat:@"(attr1 != %@) AND (attr2 != %@)", @"", [NSDate new], nil];
NSFetchRequest *query = [[NSFetchRequest alloc] initWithEntityName:@"Entity"];
query.predicate = pred;
query.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"attr1" ascending:NO]];
frc = [[NSFetchedResultsController alloc] initWithFetchRequest:query managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
frc.delegate = self;
[frc performFetch:&error];
// Output #1
NSLog(@"Rows - %ld", frc.fetchedObjects.count);
[self saveContext];
return YES;
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
NSLog(@"Rows - %ld (Update)", controller.fetchedObjects.count);
}
Edit:
Modifying the predicate seems to fix it. Still no idea why:
NSPredicate *pred = [NSPredicate predicateWithFormat:@"((attr1 = NULL) OR (attr1 != %@)) AND ((attr2 = NULL) OR (attr2 != %@))", @"", date];
Yes, I would suspect it has to do with your predicate. I think the behavior of nil
as the substitution object is unpredictable. You can either use NULL
or nil
in the format string itself or a real object that represents null, i.e. [NSNull null]
. If you try this, maybe your original predicate will also work.
But there is something else going on. Perhaps your entity has some default values that make the predicate fail, which could explain why the save could change the fetch result under certain circumstances. Also, it is not clear what the content of the saveContext
method is.
Also, not that [NSDate new]
produces a date that is accurate to 1/10000th of a second, so this part of the predicate should always return true
.