【发布时间】:2020-04-08 14:13:21
【问题描述】:
我正在尝试起草一个可重用的类,该类基本上可以被几个具有几乎相同实现的实体重用。
基本上我将有几个UIViewControllers,每个都包含UIView,其中包含UITableView,其自定义参数用于由相同managedObjectContext管理的不同实体,但具有可重复使用的NSFetchedResultsController。
第一个问题:我的方法是保留UITableView 的循环吗?所以我在继承自CoreManager 的委托类中使用了weak var tableView: UITableView,并将在@987654329 中初始化@ 与实现的UITableView 一起处理TableViewDataSource 中的所有不变性。我对这种方法存有疑问,我想就如何实现它获得一些指导,这样我就不会引入内存泄漏。
第二个问题:在我的TableViewManager 类中,基本上我会尝试显式地实现我的自定义代码,最终将在自定义UIView 中,我也不确定这是否是一个很好的方法。
注意:请原谅我有限的经验,下面的代码只是草稿,不完整。
class CoreManager<ManagedObject: NSManagedObject> : NSObject, NSFetchedResultsControllerDelegate{
var entityName: String?
weak var managedObject : ManagedObject?
lazy var authManager = AuthManager()
var fetchPredicate: NSPredicate?
var fetchRequest: NSFetchRequest<ManagedObject> = NSFetchRequest<ManagedObject>(entityName: ManagedObject.entity().managedObjectClassName)
var fetchedResultsController: NSFetchedResultsController<ManagedObject>
init(entityName: String, fetchRequest: NSFetchRequest<ManagedObject>, sectionNameKeyPath: String?, cacheName: String?) {
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedContext, sectionNameKeyPath: sectionNameKeyPath, cacheName: cacheName)
super.init()
fetchedResultsController.delegate = self
do { try fetchedResultsController.performFetch()
} catch {
fatalError("Failed to fetch entities: \(error)")
}
}
func setPredicate(predicate: NSPredicate){
fetchPredicate = predicate
}
}
问题一相关的代码
class TableViewDataSource: CoreManager<NSManagedObject>,UITableViewDataSource{
weak var tableView: UITableView!
func referenceTableView(tableview: UITableView){
self.tableView = tableview
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let sections = fetchedResultsController.sections else {
return 0
}
let sectionInfo = sections[section]
return sectionInfo.numberOfObjects
}
//FIXME: IMPLEMENT DEQUEUE CELL
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return tableView.dequeueReusableCell(withIdentifier: "cell")!
}
func numberOfSections(in tableView: UITableView) -> Int {
if let count = fetchedResultsController.sections?.count {
return count
}
return 1
}
var identifier : String?
func cellIdentifierString() -> String {
return identifier ?? ""
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
let section = IndexSet(integer: sectionIndex)
switch type {
case .delete:
tableView.deleteSections(section, with: .fade)
case .insert:
tableView.insertSections(section, with: .automatic)
case .update:
tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
tableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
case .move:
tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
tableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
@unknown default:
print()
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch (type) {
case .insert:
if let newIndexPath = newIndexPath {
tableView.insertRows(at: [newIndexPath], with: .fade)
}
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
}
case .update:
guard let indexPath = indexPath else { return }
tableView.reloadRows(at: [indexPath], with: .automatic)
case .move:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
}
if let newIndexPath = newIndexPath {
tableView.insertRows(at: [newIndexPath], with: .fade)
} default: return
}
}
}
protocol TableViewManagerDelegate: class {
func handleDelete(at indexPath: IndexPath)
func handleSwipeAction(at indexPath: IndexPath) -> UISwipeActionsConfiguration
}
class TableViewManager: TVDelegation, TableViewManagerDelegate {
//FIXME: Implement deleting
func handleDelete(at indexPath: IndexPath) {
}
//FIXME: Implement Actions
func handleSwipeAction(at indexPath: IndexPath) -> UISwipeActionsConfiguration{
let action = UIContextualAction(style: .normal, title: "Action", handler: { [weak self] action, view, completion in
completion(true)
})
let configuration = UISwipeActionsConfiguration(actions: [action])
return configuration
}
}
下面和上面的代码与问题二相关。
class TVDelegation: TableViewDataSource, UITableViewDelegate{
weak var delegateManager : TableViewManagerDelegate?
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if let sections = fetchedResultsController.sections {
let currentSection = sections[section]
return currentSection.name
}
return nil
}
//FIXME: - IMPLEMENT NAVIGATION TO DETAILCONTROLLER
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
fetchedResultsController.object(at: indexPath)
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "") {[weak self] action, view , completion in
self?.delegateManager?.handleDelete(at: indexPath)
completion(true)
}
deleteAction.image = UIImage(named: "trash")?.withRenderingMode(.alwaysTemplate)
let swipeConfig = UISwipeActionsConfiguration(actions: [deleteAction])
return swipeConfig
}
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
return delegateManager?.handleSwipeAction(at: indexPath)
}
}
【问题讨论】:
标签: ios swift uitableview core-data