Ios 如何在多视图控制器中使用NSFetchedResultsControllerDelegate而不重复控制器代码?

Ios 如何在多视图控制器中使用NSFetchedResultsControllerDelegate而不重复控制器代码?,ios,swift,inheritance,core-data,nsfetchedresultscontroller,Ios,Swift,Inheritance,Core Data,Nsfetchedresultscontroller,我正在制作一个使用核心数据的应用程序,碰巧在这个应用程序中,我有三个使用不同数据填充的TableView,它们都位于不同的控制器中,为了避免重复代码(因为它完全相同),我希望有一个解决方案 我尝试了各种协议,并使用了从UIViewController继承的MainController,而UIViewController又扩展了NSFetchedResultsControllerDelegate。 我几乎可以肯定的是,做一个超级类,我可以把这些代码放在那里是解决方案,但因为我是swift和编程新手

我正在制作一个使用核心数据的应用程序,碰巧在这个应用程序中,我有三个使用不同数据填充的TableView,它们都位于不同的控制器中,为了避免重复代码(因为它完全相同),我希望有一个解决方案

我尝试了各种协议,并使用了从UIViewController继承的MainController,而UIViewController又扩展了NSFetchedResultsControllerDelegate。 我几乎可以肯定的是,做一个超级类,我可以把这些代码放在那里是解决方案,但因为我是swift和编程新手,我也可以肯定的是,有一些事情我并没有按照预期去做

在父类中,我制作了如下内容:

class MainController: UIViewController, NSFetchedResultsController {

     var activeTableView: UITableView?
}
在孩子身上:

class SecdController: MainController {

   @IBOutlet weak var tableView: UITableView!

   override var activeTableView: UITableView? {
     get {return tableView}
     set {}
  }
}
下面是我想称之为三个控制器的代码

extension SomeController: NSFetchedResultsControllerDelegate {

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {

        switch type {

        case .insert:
            tableView.insertRows(at: [newIndexPath!], with: .top)
            break
        case .delete:
            tableView.deleteRows(at: [indexPath!], with: .fade)
            break
        case .update:
            tableView.reloadRows(at: [indexPath!], with: .top)
        case .move:
            tableView.reloadRows(at: [indexPath!], with: .top)
        default:
            fatalError("feature not yet implemented")
        }
    }

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {

        let indexSet = IndexSet(integer: sectionIndex)

        switch type {

        case .insert:
            tableView.insertSections(indexSet, with: .top)
        case .delete:
            tableView.deleteSections(indexSet, with: .top)
        case .update, .move:
            fatalError("Invalid change.")
        default:
            fatalError("feature not yet implemented")
        }
    }

    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {

        tableView.beginUpdates()
    }
    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {

        tableView.endUpdates()
    }
}
扩展SomeController:NSFetchedResultsControllerDelegate{
func控制器(controller:NSFetchedResultsController,didChange anObject:Any,在indexPath:indexPath?处,对于类型:NSFetchedResultsChangeType,newIndexPath:indexPath?){
开关类型{
案例.插入:
tableView.insertRows(位于:[newIndexPath!],带:.top)
打破
案例.删除:
tableView.deleteRows(位于:[indexPath!],带:.fade)
打破
案例。更新:
tableView.reloadRows(位于:[indexPath!],带:.top)
案件.动议:
tableView.reloadRows(位于:[indexPath!],带:.top)
违约:
fatalError(“功能尚未实现”)
}
}
func控制器(控制器:NSFetchedResultsController,didChange sectionInfo:NSFetchedResultsSectionInfo,atSectionIndex sectionIndex:Int,类型:NSFetchedResultsChangeType){
让indexSet=indexSet(整数:sectionIndex)
开关类型{
案例.插入:
tableView.insertSections(索引集,带:.top)
案例.删除:
tableView.deleteSections(索引集,带:.top)
case.update、.move:
fatalError(“无效更改”)
违约:
fatalError(“功能尚未实现”)
}
}
func controllerWillChangeContent(\ucontroller:NSFetchedResultsController){
tableView.beginUpdate()
}
func controllerDidChangeContent(\控制器:NSFetchedResultsController){
tableView.endUpdates()
}
}

提前感谢:)

您的
main控制器应该处理
NSFetchedResultsControllerDelegate
而不是继承
NSFetchedResultsController


class MainController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    var fetchedResultsController: NSFetchedResultsController<NSManagedObject>?

override func viewDidLoad() {
        super.viewDidLoad()

        setupFetchedResultsController()

       fetchedResultsController?.delegate = self
       // perform fetch
    }

func setupFetchedResultsController() {
        preconditionFailure("The method must be overridden and initialize the fetch result controller.")
    }
}

extension MainController: NSFetchedResultsControllerDelegate {

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {

// Do not force unwrap
        switch type {

        case .insert:
            tableView.insertRows(at: [newIndexPath!], with: .top)
            break
        case .delete:
            tableView.deleteRows(at: [indexPath!], with: .fade)
            break
        case .update:
            tableView.reloadRows(at: [indexPath!], with: .top)
        case .move:
            tableView.reloadRows(at: [indexPath!], with: .top)
        default:
            fatalError("feature not yet implemented")
        }
    }

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {

        let indexSet = IndexSet(integer: sectionIndex)

        switch type {

        case .insert:
            tableView.insertSections(indexSet, with: .top)
        case .delete:
            tableView.deleteSections(indexSet, with: .top)
        case .update, .move:
            fatalError("Invalid change.")
        default:
            fatalError("feature not yet implemented")
        }
    }

    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {

        tableView.beginUpdates()
    }
    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {

        tableView.endUpdates()
    }
}


这是一个棘手的问题,因为将委托重构到自己的类的常规解决方案不起作用,因为该类需要同时处理表委托(即UITableViewController)和获取控制器委托。谢天谢地,有一个简单的解决方案,就是使用一种叫做合成的技术。将复制的表放入一个
UITableViewController
子类中,该子类实现了
NSFetchedResultsControllerDelegate
,并生成一个
fetchedResultsController
属性(如下图右侧所示)

对于不同的代码,请针对每个特定情况将其放入几个
UIViewController
子类(如下图左侧所示)

使用嵌入序列使此视图控制器包含表控制器。在
viewdiload
中创建fetch控制器并将其设置为table控制器。e、 g

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if([segue.identifier isEqualToString:@"embed"]){
        self.fetchedTableViewController = segue.destinationViewController;
    }
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.fetchedTableViewController.fetchedResultsController = self.fetchedResultsController;

    // optional for more customization
    self.fetchedTableViewController.tableView.delegate = self;
    self.fetchedTableViewController.tableView.dataSource = self; 
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.fetchedTableViewController controllerDidChangeContent:controller];
如果您想处理某些特定的表或获取委托方法,那么一种巧妙的方法是将视图控制器设置为委托,然后将任何方法调用转发给嵌入式表控制器。e、 g

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if([segue.identifier isEqualToString:@"embed"]){
        self.fetchedTableViewController = segue.destinationViewController;
    }
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.fetchedTableViewController.fetchedResultsController = self.fetchedResultsController;

    // optional for more customization
    self.fetchedTableViewController.tableView.delegate = self;
    self.fetchedTableViewController.tableView.dataSource = self; 
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.fetchedTableViewController controllerDidChangeContent:controller];
在这种情况下,您还应该为Selector实现
ForwardingTargetFor模式,以确保其他所有内容也被转发

- (id)forwardingTargetForSelector:(SEL)aSelector{
    if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDelegate), aSelector)){
        if([self.fetchedTableViewController respondsToSelector:aSelector]){
            return self.fetchedTableViewController;
        }
    }
    else if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDataSource), aSelector)){
        if([self.fetchedTableViewController respondsToSelector:aSelector]){
            return self.fetchedTableViewController;
        }
    }
    else if(MHFProtocolHasInstanceMethod(@protocol(NSFetchedResultsControllerDelegate), aSelector)){
        if([self.fetchedTableViewController respondsToSelector:aSelector]){
            return self.fetchedTableViewController;
        }
    }
    else if(MHFProtocolHasInstanceMethod(@protocol(UIDataSourceModelAssociation), aSelector)){
        if([self.fetchedTableViewController respondsToSelector:aSelector]){
            return self.fetchedTableViewController;
        }
    }
    return [super forwardingTargetForSelector:aSelector];
}

- (BOOL)respondsToSelector:(SEL)aSelector{
    if([super respondsToSelector:aSelector]){
        return YES;
    }
    else if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDelegate), aSelector)){
        if([self.fetchedTableViewController respondsToSelector:aSelector]){
            return YES;
        }
    }
    else if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDataSource), aSelector)){
        if([self.fetchedTableViewController respondsToSelector:aSelector]){
            return YES;
        }
    }
    else if(MHFProtocolHasInstanceMethod(@protocol(NSFetchedResultsControllerDelegate), aSelector)){
        if([self.fetchedTableViewController respondsToSelector:aSelector]){
            return YES;
        }
    }
    else if(MHFProtocolHasInstanceMethod(@protocol(UIDataSourceModelAssociation), aSelector)){
        if([self.fetchedTableViewController respondsToSelector:aSelector]){
            return YES;
        }
    }
    return NO;
}
您,先生,您救了我:)但我必须为每个实体使用fetchedResultsController,泛型类型需要更多时间,这是我没有的宝贵时间。编译器强迫我放下大量的东西和错误