Skip to content

Instantly share code, notes, and snippets.

@adamahrens
Created January 3, 2017 20:15
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 adamahrens/411b185c4e6eb9d33b4547bfe5852954 to your computer and use it in GitHub Desktop.
Save adamahrens/411b185c4e6eb9d33b4547bfe5852954 to your computer and use it in GitHub Desktop.
//: Playground - noun: a place where people can play
import UIKit
import CoreData
protocol MangedObjectContextSettable: class {
var managedObjectContext: NSManagedObjectContext! { get set }
}
protocol ManagedObjectType: class {
associatedtype T: NSFetchRequestResult
static var entityName: String { get }
static var defaultSortDescriptors: [NSSortDescriptor] { get }
static var defaultFetchRequest: NSFetchRequest<T> { get }
}
protocol DataProvider: class {
associatedtype T
func object(at: IndexPath) -> T
func numberOfItems(section: Int) -> Int
}
protocol DataProviderDelegate: class {
associatedtype E
func dataProviderDidUpdate(updates: [DataProviderUpdate<E>]?)
}
enum DataProviderUpdate<E> {
case Insert(IndexPath)
case Update(IndexPath, E)
case Move(IndexPath, IndexPath)
case Delete(IndexPath)
}
// Base Class
class ManagedObject: NSManagedObject {
static var entityName: String = String(describing: self)
}
// Subclass
class Dog: ManagedObject, ManagedObjectType {
@NSManaged public private(set) var name: String
@NSManaged public private(set) var breed: String
static var defaultSortDescriptors: [NSSortDescriptor] {
let sort = NSSortDescriptor(key: #keyPath(Dog.breed), ascending: false)
return [sort]
}
static var defaultFetchRequest: NSFetchRequest<Dog> {
let entityName = self.entityName
let request = NSFetchRequest<Dog>(entityName: entityName)
request.sortDescriptors = defaultSortDescriptors
request.fetchBatchSize = 30
return request
}
}
// Data Provider
class FetchedResultsDataProvider<T: NSFetchRequestResult>: NSObject, NSFetchedResultsControllerDelegate, DataProvider {
private let fetchedResultsController: NSFetchedResultsController<T>
private var updates = [DataProviderUpdate<T>]()
// I want a delegate that is bound to my generic type T
//weak var delegate: DataProviderDelegate<T>?
init(fetchRequest: NSFetchRequest<T>, managedObjectContext: NSManagedObjectContext) {
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController = frc
super.init()
fetchedResultsController.delegate = self
try! fetchedResultsController.performFetch()
}
//MARK: DataProvider
func object(at: IndexPath) -> T {
return fetchedResultsController.object(at: at)
}
func numberOfItems(section: Int) -> Int {
guard let count = fetchedResultsController.sections?[section].numberOfObjects else { return 0 }
return Int(count)
}
//MARK: NSFetchedResultsControllerDelegate
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
updates.removeAll()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
// Then I pass the delegate my changes
// However this won't work
//delegate?.dataProviderDidUpdate(updates)
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
guard let indexPath = indexPath else { fatalError("Index path should be not nil") }
switch type {
case .insert :
updates.append(.Insert(indexPath))
case .delete :
updates.append(.Delete(indexPath))
case .update :
let object = self.object(at: indexPath)
updates.append(.Update(indexPath, object))
case .move :
guard let newIndexPath = newIndexPath else { fatalError("New Index Path should not be nil") }
updates.append(.Move(indexPath, newIndexPath))
}
}
}
class ViewController: UIViewController, MangedObjectContextSettable, UITableViewDataSource, DataProviderDelegate {
var managedObjectContext: NSManagedObjectContext!
private var dataProvider: FetchedResultsDataProvider<Dog>!
//MARK: View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
let request = Dog.defaultFetchRequest
dataProvider = FetchedResultsDataProvider<Dog>(fetchRequest: request, managedObjectContext: managedObjectContext)
}
//MARK: UITableViewDataSource
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataProvider.numberOfItems(section: section)
}
//MARK: DataProviderDelegate
func dataProviderDidUpdate(updates: [DataProviderUpdate<Dog>]?) {
}
}
print("All Good")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment