- (instancetype)initWithTableView:(UITableView *)tableView fetchedResultsController:(NSFetchedResultsController *)fetchedResultsController {
NSParameterAssert(tableView != nil);
NSParameterAssert(fetchedResultsController != nil);
if (self = [super init]) {
_tableView = tableView;
tableView.dataSource = self;
_fetchedResultsController = fetchedResultsController;
_fetchedResultsController.delegate = self;
}
return self;
}
- (instancetype)initWithTableView:(UITableView *)tableView managedObjectContext:(NSManagedObjectContext *)managedObjectContext fetchRequest:(NSFetchRequest *)fetchRequest sectionNameKeyPath:(NSString *)sectionNameKeyPath cacheName:(NSString *)cacheName {
NSParameterAssert(managedObjectContext != nil);
NSParameterAssert(fetchRequest != nil);
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:sectionNameKeyPath cacheName:cacheName];
return [self initWithTableView:tableView fetchedResultsController:fetchedResultsController];
}
- (NSManagedObjectContext *)managedObjectContext {
return [_fetchedResultsController managedObjectContext];
}
- (NSFetchRequest *)fetchRequest {
return [_fetchedResultsController fetchRequest];
}
- (BOOL)performFetch:(NSError **)error {
BOOL result = [self.fetchedResultsController performFetch:error];
[self.tableView reloadData];
return result;
}
#pragma mark -
- (id )sectionInfoForSection:(NSUInteger)section {
return self.fetchedResultsController.sections[section];
}
- (id )objectAtIndexPath:(NSIndexPath *)indexPath {
return [self sectionInfoForSection:indexPath.section].objects[indexPath.row];
}
#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:sectionIndex];
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
case NSFetchedResultsChangeMove:
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate: {
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSUInteger count = [self.fetchedResultsController.sections count];
return (NSInteger)count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id sectionInfo = [self sectionInfoForSection:section];
return (NSInteger)sectionInfo.numberOfObjects;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.cellForManagedObject == nil) {
NSString *reason = [NSString stringWithFormat:@"%@: You must override %@ or set %@", NSStringFromClass([self class]), NSStringFromSelector(@selector(tableView:cellForRowAtIndexPath:)), NSStringFromSelector(@selector(cellForManagedObject))];
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:reason userInfo:nil];
}
NSManagedObject *managedObject = [self objectAtIndexPath:indexPath];
return self.cellForManagedObject(tableView, indexPath, managedObject);
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[self sectionInfoForSection:section] name];
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
return nil;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
switch (editingStyle) {
case UITableViewCellEditingStyleDelete: {
NSManagedObject *managedObject = [self objectAtIndexPath:indexPath];
[self.managedObjectContext deleteObject:managedObject];
NSError *error;
if ([self.managedObjectContext save:&error] == NO) {
NSLog(@"%@: Failed to save managed object context after deleting %@", NSStringFromClass([self class]), error);
}
break;
}
case UITableViewCellEditingStyleInsert:
break;
case UITableViewCellEditingStyleNone:
break;
}
}