Jake Hansen
Jake Hansen

Reputation: 25

Core Data, UITableView, and UISegmentedControl

I am new to working with Core Data, and am working with a UITableView. I have a toolbar with a UISegmentedController, and I want to filter the items in the UITableView based on the selected index. In other words, suppose I have a UITableView that displays Books (stored in Core Data) and a UISegmentedController with segments to display books in "English", "Spanish", and "French".

What is the approach here to get everything hooked up? When one of the segments is clicked, what do I do in the UISegmentedControl's target to change things around?

Sorry if it's a stupid question!

Upvotes: 2

Views: 1526

Answers (4)

Carrie Hall
Carrie Hall

Reputation: 931

I have implemented this as follows using the guidelines from Marcus above(I'm new to this so it may not be the best approach). I have a segment controller with three options for 'open', 'in progress' and 'closed'.

In the ViewController.h, create an iVar for each one of your segment options, and one iVar for the main controller that will store the current controller.

@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;

@property (nonatomic, retain) NSFetchedResultsController *inprogressFetchedResultsController;
@property (nonatomic, retain) NSFetchedResultsController *openFetchedResultsController;
@property (nonatomic, retain) NSFetchedResultsController *closedFetchedResultsController;

In the ViewController.m you need to create methods for lazy loading of these controllers, so I have three in total. They are basically the same except for the predicate and the cacheName, I have only shown one below.

- (NSFetchedResultsController *)closedFetchedResultsController
{
    if (_closedFetchedResultsController != nil) {
        return _closedFetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Ticket" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"priority.name" ascending:NO];
    NSArray *sortDescriptors = @[sortDescriptor];

    [fetchRequest setSortDescriptors:sortDescriptors];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = 'Closed'"];
    [fetchRequest setPredicate:predicate];

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"priority.name" cacheName:@"ClosedTickets"];
    aFetchedResultsController.delegate = self;

    self.closedFetchedResultsController = aFetchedResultsController;

    NSError *error = nil;
    if (![self.closedFetchedResultsController 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.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _closedFetchedResultsController;
}

Create an IBAction for your segment so that when it is changed it changes the fetched results controller and reloads the table.

- (IBAction)statusChanged:(id)sender {
    switch (self.segmentControl.selectedSegmentIndex) {
        case 0:
            self.fetchedResultsController = self.inprogressFetchedResultsController;
            break;
        case 1:
            self.fetchedResultsController = self.openFetchedResultsController;
            break;
        case 2:
            self.fetchedResultsController = self.closedFetchedResultsController;
            break;
        default:
            break;

    }
    [self.tableView reloadData];
}

That's it!

N.B. I also added this line to my ViewDidLoad method so that it would load the correct option into the fetchedResultsController initially.

self.fetchedResultsController = self.inprogressFetchedResultsController;

Upvotes: 0

Marcus S. Zarra
Marcus S. Zarra

Reputation: 46718

I would use a separate NSFetchedResultsController for each segment. This will allow you to take advantage of the built in cache for each segment and improve performance.

In addition to Apple's documentation (and my book), you can also read up on them from my article Touching The Core in the PragPub magazine.

Upvotes: 6

jamapag
jamapag

Reputation: 9318

You can use NSFetchedResultsController, when you clicked on segment just set the different perdicate and perform fetch again.

Upvotes: 0

PaulWoodIII
PaulWoodIII

Reputation: 2656

Its a good idea to use three different Arrays for each of your filters. Cache them somewhere so their is no delay when the user selects a filter. To find the information you are looking for from your CoreData store use NSPredicate.

Upvotes: 0

Related Questions