Search code examples
iosuitableviewconcurrencynsfetchedresultscontrollernsmanagedobjectcontext

Why do I have to comment out my NSPredicate to have NSFetchedResultsController populate an UITableView?


I have a strange bug: if I uncomment my NSPredicate, the resulting UITableView is empty.

My data Model is the following: Category <-->> Feed <-->> Post

I am fetching the Posts. Post.feed is a Post's Feed. Feed has an rss NString property.

Here's the code:

    - (NSFetchedResultsController *)fetchedResultsController {

        // Set up the fetched results controller if needed.
        if (_fetchedResultsController == nil) {
            // Create the fetch request for the entity.
            NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
            // Edit the entity name as appropriate.
            NSEntityDescription *entity = [NSEntityDescription entityForName:@"Post"
                                                      inManagedObjectContext:_globalMOC];
            [fetchRequest setEntity:entity];

            // Edit the sort key as appropriate.
            NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
            NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
            [fetchRequest setSortDescriptors:sortDescriptors];

            NSPredicate *predicate =[NSPredicate predicateWithFormat:@"feed.rss == %@",  _detailItem.rss];
            [fetchRequest setPredicate:predicate];

            // Edit the section name key path and cache name if appropriate.
            // nil for section name key path means "no sections".
            NSFetchedResultsController *aFetchedResultsController =
            [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                managedObjectContext:_globalMOC
                                                  sectionNameKeyPath:nil
                                                           cacheName:nil];
            self.fetchedResultsController = aFetchedResultsController;

            self.fetchedResultsController.delegate = self;

            NSError *error = nil;

            if (![self.fetchedResultsController performFetch:&error]) {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate.
                // You should not use this function in a shipping application, although it may be useful
                // during development. If it is not possible to recover from the error, display an alert
                // panel that instructs the user to quit the application by pressing the Home button.
                //
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }

        }

        return _fetchedResultsController;
    }

As I told before, I only see results if I uncomment the NSPredicate. I tried with LIKE, ==, =, with double and single quotes around %@...

BTW, The best would be to directly compare the Feed object...

According to Apple, the syntax might not be the issue, but then what?

The Posts are created in a separate ManagedObjectController sharing the same PersistentStoreCoordinator. I get the required Feed's objectID in order to associate the new Post with its corresponding Feed in the child MOC (otherwise I'd get an error regarding associating objects from different MOC).

I also duely merge my MOCs in the main thread whenever the child MOC notifies it of a change.

Basically: if I NSLog the Posts I have (commented-NSPredicate), I see every Post with the relevant RSS Feed URL fitting the displayed Feed (= detailItem).

Anyone can help me?


Solution

  • Eureka!

    The problem was the following: when I create my NSFetchedResultsController in my DetailView, _detailItem is nil.

    So, even after when setting _detailItem, the NSPredicate still focus on comparing my feed relationship to a nil object.

    I solved the problem by refreshing my NSFetchedResultsController.fetchRequest in the didSelectRowAtIndexPath in the MasterView the following way:

        Feed *feed;
        if (tableView == self.searchDisplayController.searchResultsTableView) {
            feed = [_filteredCategoryArray objectAtIndex:indexPath.row];
        } else {
            feed = [[self fetchedResultsController] objectAtIndexPath:indexPath];
        }
        self.detailViewController.detailItem = feed;
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"feed == %@", feed];
        [self.detailViewController.fetchedResultsController.fetchRequest setPredicate:predicate];
    

    Hope this solution might help other people.

    Thanks for your help, nickAtStack!