Last active
December 25, 2015 17:09
-
-
Save infradust/7010837 to your computer and use it in GitHub Desktop.
a table view with 2 FRCs as data sources sharing a context and pointing to the same data with different predicates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "MasterViewController.h" | |
#import "DetailViewController.h" | |
#import "Event.h" | |
#import "NSManagedObject+utils.h" | |
@interface MasterViewController () | |
{ | |
NSUInteger _updatingTable; | |
} | |
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath; | |
@end | |
@implementation MasterViewController | |
- (void)awakeFromNib | |
{ | |
self.clearsSelectionOnViewWillAppear = NO; | |
self.preferredContentSize = CGSizeMake(320.0, 600.0); | |
[super awakeFromNib]; | |
} | |
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
// Do any additional setup after loading the view, typically from a nib. | |
self.navigationItem.leftBarButtonItem = self.editButtonItem; | |
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)]; | |
self.navigationItem.rightBarButtonItem = addButton; | |
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController]; | |
id x = self.mainFetchedResultsController; | |
x = self.filteredFetchedResultsController; | |
} | |
- (void)didReceiveMemoryWarning | |
{ | |
[super didReceiveMemoryWarning]; | |
// Dispose of any resources that can be recreated. | |
} | |
- (void)insertNewObject:(id)sender | |
{ | |
NSManagedObjectContext *context = [self managedObjectContext]; | |
[Event createWithConfigBlock:^(Event *obj, NSUInteger index) { | |
obj.n =@(rand()%2); | |
obj.name = [NSString stringWithFormat:@"%i%i%i",rand()%10,rand()%10,rand()%10]; | |
} context:context]; | |
NSError *error = nil; | |
if (![context save:&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(); | |
} | |
} | |
#pragma mark - Table View | |
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView | |
{ | |
return 2; | |
} | |
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section | |
{ | |
NSFetchedResultsController* controller = (section ? self.mainFetchedResultsController : self.filteredFetchedResultsController); | |
id <NSFetchedResultsSectionInfo> sectionInfo = [controller sections][0]; | |
return [sectionInfo numberOfObjects]; | |
} | |
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath | |
{ | |
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; | |
[self configureCell:cell atIndexPath:indexPath]; | |
return cell; | |
} | |
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath | |
{ | |
// Return NO if you do not want the specified item to be editable. | |
return YES; | |
} | |
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath | |
{ | |
if (editingStyle == UITableViewCellEditingStyleDelete) { | |
NSManagedObjectContext *context = self.managedObjectContext; | |
[context deleteObject:[self objectAtIndexPath:indexPath]]; | |
NSError *error = nil; | |
if (![context save:&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(); | |
} | |
} | |
} | |
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath | |
{ | |
// The table view should not be re-orderable. | |
return NO; | |
} | |
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath | |
{ | |
NSManagedObject *object = [self objectAtIndexPath:indexPath]; | |
self.detailViewController.detailItem = object; | |
} | |
- (NSFetchedResultsController*) fetchedResultsController:(NSIndexPath*)indexPath | |
{ | |
if (indexPath.section == 1) { | |
return self.mainFetchedResultsController; | |
} | |
return self.filteredFetchedResultsController; | |
} | |
- (NSManagedObject*) objectAtIndexPath:(NSIndexPath*)indexPath | |
{ | |
NSFetchedResultsController* controller = [self fetchedResultsController:indexPath]; | |
NSIndexPath* newIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:0]; | |
return [controller objectAtIndexPath:newIndexPath]; | |
} | |
#pragma mark - Fetched results controller | |
- (NSFetchedResultsController *) mainFetchedResultsController | |
{ | |
if (_mainFetchedResultsController != nil) { | |
return _mainFetchedResultsController; | |
} | |
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; | |
// Edit the entity name as appropriate. | |
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext]; | |
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"n == 0 OR n == 1"]]; | |
[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:@"name" ascending:NO]; | |
NSArray *sortDescriptors = @[sortDescriptor]; | |
[fetchRequest setSortDescriptors:sortDescriptors]; | |
// 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:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; | |
aFetchedResultsController.delegate = self; | |
self.mainFetchedResultsController = aFetchedResultsController; | |
NSError *error = nil; | |
if (![self.mainFetchedResultsController 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 _mainFetchedResultsController; | |
} | |
- (NSFetchedResultsController*) filteredFetchedResultsController | |
{ | |
if (_filteredFetchedResultsController != nil) { | |
return _filteredFetchedResultsController; | |
} | |
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; | |
// Edit the entity name as appropriate. | |
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext]; | |
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"n == 0"]]; | |
[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:@"name" ascending:NO]; | |
NSArray *sortDescriptors = @[sortDescriptor]; | |
[fetchRequest setSortDescriptors:sortDescriptors]; | |
// 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:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; | |
aFetchedResultsController.delegate = self; | |
self.filteredFetchedResultsController = aFetchedResultsController; | |
NSError *error = nil; | |
if (![self.filteredFetchedResultsController 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 _filteredFetchedResultsController; | |
} | |
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller | |
{ | |
if (_updatingTable == 0) { | |
[self.tableView beginUpdates]; | |
} | |
_updatingTable++; | |
} | |
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject | |
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type | |
newIndexPath:(NSIndexPath *)newIndexPath | |
{ | |
UITableView *tableView = self.tableView; | |
if (controller != self.filteredFetchedResultsController) { | |
indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:1]; | |
if (newIndexPath) { | |
newIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row inSection:1]; | |
} | |
} | |
switch(type) { | |
case NSFetchedResultsChangeInsert: | |
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; | |
break; | |
case NSFetchedResultsChangeDelete: | |
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; | |
break; | |
case NSFetchedResultsChangeUpdate: | |
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; | |
break; | |
case NSFetchedResultsChangeMove: | |
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; | |
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; | |
break; | |
} | |
} | |
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller | |
{ | |
_updatingTable--; | |
if (_updatingTable == 0) { | |
[self.tableView endUpdates]; | |
} | |
} | |
/* | |
// Implementing the above methods to update the table view in response to individual changes may have performance implications if a large number of changes are made simultaneously. If this proves to be an issue, you can instead just implement controllerDidChangeContent: which notifies the delegate that all section and object changes have been processed. | |
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller | |
{ | |
// In the simplest, most efficient, case, reload the table view. | |
[self.tableView reloadData]; | |
} | |
*/ | |
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath | |
{ | |
NSManagedObject *object = [self objectAtIndexPath:indexPath]; | |
cell.textLabel.text = [NSString stringWithFormat:@"%@-%@",[object valueForKey:@"name"],[object valueForKey:@"n"]]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very helpful. This is just what I was looking for. Thanks for posting!