Created
January 3, 2017 20:15
-
-
Save adamahrens/411b185c4e6eb9d33b4547bfe5852954 to your computer and use it in GitHub Desktop.
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
//: 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