Last active
September 8, 2022 12:29
-
-
Save Sorix/8bda87efdf46c9beb0ff3daf258da564 to your computer and use it in GitHub Desktop.
UITableViewDataSource boilerplate with NSFetchedResultsController
This file contains hidden or 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 UIKit | |
import CoreData | |
public protocol FetchedResultsDelegate { | |
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: AnyObject) -> UITableViewCell | |
} | |
public class FetchedResultsDataSource: NSObject, UITableViewDataSource, NSFetchedResultsControllerDelegate { | |
public weak var tableView: UITableView? | |
public var frc: NSFetchedResultsController | |
public var delegate: FetchedResultsDelegate? | |
public init(fetchRequest: NSFetchRequest, context: NSManagedObjectContext = DataController.dataStack.mainContext, sectionNameKeyPath: String?) { | |
frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: sectionNameKeyPath, cacheName: nil) | |
super.init() | |
frc.delegate = self | |
} | |
/// Set `tableView.datasource` to `self`, perform fetch and reload table data | |
public func performFetchAndConfigureTableView(tableView: UITableView) { | |
self.tableView = tableView | |
tableView.dataSource = self | |
do { | |
try frc.performFetch() | |
dispatch_async(dispatch_get_main_queue()) { tableView.reloadData() } | |
} catch { | |
assertionFailure("\(#function): \(error)") | |
} | |
} | |
public func objectAtIndexPath(indexPath: NSIndexPath) -> AnyObject { | |
return frc.objectAtIndexPath(indexPath) | |
} | |
public func titleForHeaderInSection(section: Int) -> String? { | |
return self.frc.sections?[section].name | |
} | |
// MARK: - UITableViewDataSource | |
public func numberOfSectionsInTableView(tableView: UITableView) -> Int { | |
return self.frc.sections?.count ?? 0 | |
} | |
public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
guard let sections = frc.sections else { return 0 } | |
return sections[section].numberOfObjects | |
} | |
public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { | |
if let delegate = delegate { | |
return delegate.tableView(tableView, cellForRowAtIndexPath: indexPath, object: self.objectAtIndexPath(indexPath)) | |
} else { | |
assertionFailure("Delegate is not set, can't return cell") | |
return UITableViewCell() | |
} | |
} | |
// func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { | |
// return self.frc.sections?[section].name | |
// } | |
// MARK: - Right section titles | |
// func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int { | |
// return self.frc.sectionForSectionIndexTitle(title, atIndex: index) ?? 0 | |
// } | |
// | |
// func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? { | |
// return self.frc.sectionIndexTitles | |
// } | |
// MARK: - NSFetchedResultsControllerDelegate | |
public func controllerWillChangeContent(controller: NSFetchedResultsController) { | |
tableView?.beginUpdates() | |
} | |
public func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { | |
let sectionIndexSet = NSIndexSet(index: sectionIndex) | |
switch type { | |
case NSFetchedResultsChangeType.Insert: | |
tableView?.insertSections(sectionIndexSet, withRowAnimation: .Automatic) | |
case NSFetchedResultsChangeType.Delete: | |
tableView?.deleteSections(sectionIndexSet, withRowAnimation: .Automatic) | |
case .Update: | |
tableView?.reloadSections(sectionIndexSet, withRowAnimation: .Automatic) | |
case .Move: | |
// TODO: maybe we have better solution instead of reload, possible bugs | |
tableView?.reloadSections(sectionIndexSet, withRowAnimation: .Automatic) | |
} | |
} | |
public func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { | |
switch type { | |
case .Insert: | |
guard let newIndexPath = newIndexPath else { return } | |
tableView?.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Automatic) | |
case .Delete: | |
guard let indexPath = indexPath else { return } | |
tableView?.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) | |
case .Update: | |
guard let indexPath = indexPath else { return } | |
tableView?.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) | |
case .Move: | |
guard let indexPath = indexPath, let newIndexPath = newIndexPath else { return } | |
tableView?.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade) | |
tableView?.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: UITableViewRowAnimation.Fade) | |
} | |
} | |
public func controllerDidChangeContent(controller: NSFetchedResultsController) { | |
tableView?.endUpdates() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment