Skip to content

Instantly share code, notes, and snippets.

@DaveBatton
Created December 23, 2016 18:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DaveBatton/47376cdb3217fe7c37ad15352894f862 to your computer and use it in GitHub Desktop.
Save DaveBatton/47376cdb3217fe7c37ad15352894f862 to your computer and use it in GitHub Desktop.
//
// MCFetchedResultsViewController.m
// MoneyCarta
//
// Created by Dave Batton on 5/5/15.
// Copyright (c) 2015 Project Black. All rights reserved.
//
#import "MCFetchedResultsViewController.h"
#import "AppDelegate.h"
#import "UIAlertView+MCAdditions.h"
#import "MCHeaderView.h"
@interface MCFetchedResultsViewController ()
@property (nonatomic) BOOL hasDoneFirstFetch;
@end
@implementation MCFetchedResultsViewController
#pragma mark - Setup & Teardown
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_fetchedResultsManagedObjectContext = APPDELEGATE.managedObjectContext;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
_fetchedResultsManagedObjectContext = APPDELEGATE.managedObjectContext;
}
return self;
}
- (void)dealloc
{
_fetchedResultsController.delegate = nil;
_fetchedResultsController = nil;
_tableView.delegate = nil;
_tableView.dataSource = nil;
}
#pragma mark - UIViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[MCHeaderView class] forHeaderFooterViewReuseIdentifier:@"MCHeaderView"];
self.hasDoneFirstFetch = NO;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.hasDoneFirstFetch == NO) {
[self performFetch];
}
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
}
#pragma mark - Public
- (void)performFetch
{
[UIAlertView mcShowAssert:([self.fetchedResultsEntityName length] > 0) message:@"MCFetchedResultsViewController requires a fetchedResultsEntityName."];
[UIAlertView mcShowAssert:(self.fetchedResultsSortDescriptors.count > 0) message:@"MCFetchedResultsViewController requires fetchedResultsSortDescriptors."];
NSError *error;
[self.fetchedResultsController performFetch:&error];
[UIAlertView mcShowError:error];
[self.tableView reloadData];
self.hasDoneFirstFetch = YES;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
// For subclasses to override. No need to call super.
}
- (NSIndexPath *)mapIndexPathFromFetchResultsController:(NSIndexPath *)indexPath
{
return indexPath;
}
- (NSIndexPath *)mapIndexPathToFetchResultsController:(NSIndexPath *)indexPath
{
return indexPath;
}
- (NSInteger)mapSectionFromFetchResultsController:(NSInteger)section
{
return section;
}
- (NSInteger)mapSectionToFetchResultsController:(NSInteger)section
{
return section;
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.fetchedResultsController.sections.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
id<NSFetchedResultsSectionInfo> sectionInfo = self.fetchedResultsController.sections[section];
return sectionInfo.name;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id<NSFetchedResultsSectionInfo> sectionInfo = self.fetchedResultsController.sections[section];
return sectionInfo.numberOfObjects;
}
#pragma mark - UITableViewDelegate
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
return [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:@"MCHeaderView"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Subclass should override. No need to call super.
return [[UITableViewCell alloc] init];
}
#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
default:
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 configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
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 - Accessors
- (void)setFetchedResultsEntityName:(NSString *)entityName
{
[UIAlertView mcShowAssert:(_fetchedResultsController == nil) message:@"You must set fetchedResultsEntityName before the fetchedResultsController has been created."];
_fetchedResultsEntityName = entityName;
}
- (void)setFetchedResultsPredicate:(NSPredicate *)predicate
{
[UIAlertView mcShowAssert:(_fetchedResultsController == nil) message:@"You must set fetchedResultsPredicate before the fetchedResultsController has been created. After that, access its fetchRequest property directly."];
_fetchedResultsPredicate = predicate;
}
- (void)setFetchedResultsSortDescriptors:(NSArray *)sortDescriptors
{
[UIAlertView mcShowAssert:(_fetchedResultsController == nil) message:@"You must set fetchedResultsSortDescriptors before the fetchedResultsController has been created. After that, access its fetchRequest property directly."];
_fetchedResultsSortDescriptors = sortDescriptors;
}
- (void)setFetchedResultsSectionNameKeyPath:(NSString *)keyPath
{
[UIAlertView mcShowAssert:(_fetchedResultsController == nil) message:@"You must set fetchedResultsSectionNameKeyPath before the fetchedResultsController has been created."];
_fetchedResultsSectionNameKeyPath = keyPath;
}
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:self.fetchedResultsEntityName];
fetchRequest.predicate = self.fetchedResultsPredicate;
fetchRequest.sortDescriptors = self.fetchedResultsSortDescriptors;
_fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest
managedObjectContext:self.fetchedResultsManagedObjectContext
sectionNameKeyPath:self.fetchedResultsSectionNameKeyPath
cacheName:nil];
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
- (void)setFetchedResultsManagedObjectContext:(NSManagedObjectContext *)context
{
if (_fetchedResultsManagedObjectContext != context) {
[UIAlertView mcShowAssert:(_fetchedResultsController == nil) message:@"You can't change the managed object context after creating the fetched results controller."];
_fetchedResultsManagedObjectContext = context;
}
}
#pragma mark - Actions
- (IBAction)toggleEdit:(id)sender
{
[self.view endEditing:YES];
if (self.tableView.isEditing) {
[APPDELEGATE saveTemporaryContext:self.fetchedResultsController.managedObjectContext];
}
UIBarButtonSystemItem systemItem = self.tableView.isEditing ? UIBarButtonSystemItemEdit : UIBarButtonSystemItemDone;
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:systemItem
target:self
action:@selector(toggleEdit:)];
[self.tableView setEditing:!self.tableView.isEditing animated:YES];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment