Question

I am using a NSFetchedResultsController to handle the data going in and out of my UITableView. It all works fine until I put a NSPredicate on it. I need to get all Thread objects that have a relationship with at least one message that is not expired or does not have a expiration_date set yet. So I use the following predicate.

NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:@"ANY messages.expiration_date == null OR ANY messages.expiration_date > %@", [NSDate date]];

Problem is that this causes the NSFetchedResultsController to act very strange. If a thread gains a new message in its messages relationship it deletes the row. It also does not insert new ones.

I am 100% sure it is the NSPredicate causing these behaviors. Without it, everything works fine I just don't have some of the data I do not want filtered out.

Below is a picture of the talked about section of my data model. I will also include the code for my NSFetchedResultsController.

/**
 * Returns a NSFetchedResultsController for the unified inbox
 *
 * @return Controller for fetched results
 */
- (NSFetchedResultsController *)resultsControllerForUnifiedInbox
{
    NSFetchRequest      *threadsRequest = [NSFetchRequest fetchRequestWithEntityName:@"Thread"];
    NSEntityDescription *threadModel    = [NSEntityDescription entityForName:@"Thread" inManagedObjectContext:_mainManagedObjectContext];

    [threadsRequest setEntity:threadModel];

    NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:@"ANY messages.expiration_date == null OR ANY messages.expiration_date > %@", [NSDate date]];

    [threadsRequest setPredicate:threadPredicate];

    NSSortDescriptor *threadSort = [NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO];

    [threadsRequest setSortDescriptors:[NSArray arrayWithObject:threadSort]];
    [threadsRequest setFetchBatchSize:LiftFetchControllerAtrributeBatchSize];

    NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:threadsRequest
                                                                                               managedObjectContext:_mainManagedObjectContext
                                                                                                 sectionNameKeyPath:nil
                                                                                                          cacheName:nil];

    return fetchedResultsController;
}

enter image description here

Was it helpful?

Solution

I cannot explain the strange effects of the predicate that you observed, but I assume that your predicate is not doing what you expect.

[NSPredicate predicateWithFormat:@"ANY messages.expiration_date == null OR ANY messages.expiration_date > %@", [NSDate date]];

finds all threads that have a message with expiration_date not set OR have a possible different message that is not expired. What you (probably) need instead is

[NSPredicate predicateWithFormat:@"SUBQUERY(messages, $m, $m.expiration_date == null OR $m.expiration_date > %@).@count > 0", [NSDate date]];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top