AutoCat2/AutoCat2/Components/TableView/CoreDataSource.swift

114 lines
3.9 KiB
Swift

//
// CoreDataSource.swift
// AutoCat2
//
// Created by Selim Mustafaev on 27.03.2022.
//
import UIKit
import CoreData
import AutoCatCore
import DifferenceKit
protocol ConfigurableCell {
associatedtype Item
func configure(with item: Item)
}
typealias ConfigurableTableViewCell = UITableViewCell & ConfigurableCell
class CoreDataSource<Item: NSManagedObject & Dated & Differentiable, Cell: ConfigurableTableViewCell>
: NSObject, NSFetchedResultsControllerDelegate, UITableViewDataSource where Cell.Item == Item {
private let cellIdentifier: String
private let tableView: UITableView
private let fetchedResults: NSFetchedResultsController<Item>
private var sections: [DateSection<Item>] = []
init(tableView: UITableView, context: NSManagedObjectContext, cellIdentifier: String = String(describing: Cell.self)) {
self.tableView = tableView
self.cellIdentifier = cellIdentifier
if let fetchRequest = Item.fetchRequest() as? NSFetchRequest<Item> {
fetchRequest.sortDescriptors = []
self.fetchedResults = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: context,
sectionNameKeyPath: nil,
cacheName: nil)
} else {
self.fetchedResults = NSFetchedResultsController()
}
super.init()
self.tableView.dataSource = self
self.tableView.reloadData()
self.fetchedResults.delegate = self
try? self.fetchedResults.performFetch()
reload()
}
func reload() {
let items: [Item] = fetchedResults.fetchedObjects ?? []
DispatchQueue.global().async {
let newSections = items.groupedByDate()
let changeset = StagedChangeset(source: self.sections, target: newSections)
DispatchQueue.main.async {
self.tableView.reload(using: changeset, with: .fade) { newSects in
self.sections = newSects
}
}
}
}
func item(at indexPath: IndexPath) -> Item {
sections[indexPath.section].elements[indexPath.row]
}
// MARK: - NSFetchedResultsControllerDelegate
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
reload()
}
// MARK: - UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int {
return self.sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.sections[section].elements.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? Cell else {
return UITableViewCell()
}
let item = self.sections[indexPath.section].elements[indexPath.row]
cell.configure(with: item)
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section].header
}
}