Luke
Luke

Reputation: 9700

Filtering a UITableView based on an NSPredicate from an NSFetchedResultsController

I'm trying to filter objects in a UITableView, which gets its data from a Core Data sqlite via aNSFetchedResultsController. It's working fine before filtering, but now I need to be able to tap a button and have it display only objects one of whose properties (a BOOL) is YES. Lets call it isFavourite.

I'm a little confused as to where to begin. I understand the concept of a predicate, and I've constructed this one, which should work:

NSPredicate *predicate = [NSPredicate predicateWithFormat: @"isFavourite == 1"];

However, I'm a little confused as to how to attach that predicate to the NSFetchedResultsController. I already allocated and initialised it, using a separate fetch request which simply returned all objects of that entity (and that works perfectly). If it's been initialised already, can I change its fetch request? If so, how do I do that, then how do I make it re-run the query. Do I then need to manually update the UITableView with reloadData or similar. Then, what do I do when I want to switch this filter off and go back to viewing all results?

I've read a lot of existing questions here but most seem to relate to search bars, which make the answers a lot more complicated. I've also read the Apple documentation, but tend to find its written in a pretty cryptic fashion. My code is below, I'm only part-way through the filterFavourite method and that's where I'm looking for help and clarification.

- (NSFetchedResultsController *) fetchedResultsController
{
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName: @"Quote" inManagedObjectContext: [[CoreDataController sharedCoreDataController] managedObjectContext]];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey: @"quoteID" ascending: YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];

    [fetchRequest setFetchBatchSize: 50];

    NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest: fetchRequest managedObjectContext: [[FQCoreDataController sharedCoreDataController] managedObjectContext] sectionNameKeyPath: nil cacheName: nil];
    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

- (IBAction) filterFavourite: (id) sender
{
    if (isDisplayingFavourite) {
        // Switch to showing all..
        NSPredicate *predicate = [NSPredicate predicateWithFormat: @"isFavourite == 1"];

        isDisplayingFavourite = NO;
    } else {
        // Switch to showing favourites only..

        isDisplayingFavourite = YES;
    }

}

EDIT: The delegate method "controllerDidChangeContent" is never called in this code. I can't figure out why that is, either. Hugely, hugely confusing, Core Data is like a brick wall. In fact, NONE of the four delegate methods are ever called.

Upvotes: 1

Views: 1627

Answers (1)

Tom Harrington
Tom Harrington

Reputation: 70976

You don't attach a predicate to the NSFetchedResultsController-- you attach it to the NSFetchRequest. It has a method called setPredicate: that does exactly what its name suggests.

You can modify the fetch request by updating the fetchRequest attribute and calling performFetch: again. You could also nil out your fetchedResultsController ivar, and make the code above flexible enough to add whatever predicate(s) would be useful. The next time your fetchedResultsController method is called, it will create a new instance for you with the current predicate(s). That consolidates all of your NSFetchedResultsController code in one method. It's probably slightly more expensive in CPU usage but also probably easier to maintain.

Upvotes: 2

Related Questions