如何正确重构 2 个 ViewController 的重复代码?

How to properly refactor repeated code of 2 ViewControllers?

我有 1 个带有 CustomTableView 类型的 UIViewController 和 1 个带有普通 UITableView 类型的 UITableViewController。两者都符合 NSFetchedResultsControllerDelegate 并使用重复代码实现其委托方法。现在它在扩展中。

是否可以将该代码移出到单独的 swift 文件中?我试图用 class NSFetchedResultsView 将它移动到单独的文件,但是当我将该委托方法复制到新文件时,它对它的方法中的 tableView 一无所知...

如何正确分离这些方法?

我要分离的委托方法:

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

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

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch type {
    case .update:
        if let indexPath = indexPath {
            tableView.reloadRows(at: [indexPath], with: .none)
        }
    case .move:
        if let indexPath = indexPath, let newIndexPath = newIndexPath {
            tableView.moveRow(at: indexPath, to: newIndexPath)
        }
    case .delete:
        if let indexPath = indexPath {
            tableView.deleteRows(at: [indexPath], with: .none)
        }
    case .insert:
        if let newIndexPath = newIndexPath {
            tableView.insertRows(at: [newIndexPath], with: .none)
        }
    default:
        tableView.reloadData()
    }
}

您可以创建一个可以指定为委托的对象

class CommonFetchResultDelegate: NSFetchedResultsControllerDelegate {
    var tableView: UITableView

    // make init that takes the table view
    init(tableView: TableView) {
        self.tableView = tableView
    }

    // !!!implement all the other delegate functions!!!

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

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

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch type {
        case .update:
            if let indexPath = indexPath {
                tableView.reloadRows(at: [indexPath], with: .none)
            }
        case .move:
            if let indexPath = indexPath, let newIndexPath = newIndexPath {
                tableView.moveRow(at: indexPath, to: newIndexPath)
            }
        case .delete:
            if let indexPath = indexPath {
                tableView.deleteRows(at: [indexPath], with: .none)
            }
        case .insert:
            if let newIndexPath = newIndexPath {
                tableView.insertRows(at: [newIndexPath], with: .none)
            }
        default:
            tableView.reloadData()
        }
    }
}


// then in the view controller 
var myDelegate: CommonFetchResultDelegate?

override viewDidLoad() {
    super.viewDidLoad()

    self.myDelegate = CommonFetchResultDelegate(tableView: self.tableView)
    self.myDelegate = fetchResultController.delegate
}