artexhibit
artexhibit

Reputation: 319

How to properly refactor repeated code of 2 ViewControllers?

I have 1 UIViewController with a type of CustomTableView and 1 UITableViewController with a type of usual UITableView. Both conform to NSFetchedResultsControllerDelegate and implemented its delegate methods with the repeated code. For now it's in extensions.

Is it possible to move that code out to a separate swift file? I tried to move it to separate file with class NSFetchedResultsView, but when I copy that delegate methods to the new file, it doesn't know anything about tableView inside it's methods...

How can I separate that methods properly?

Delegate methods I want to separate:

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()
    }
}

Upvotes: 0

Views: 51

Answers (1)

Yogurt
Yogurt

Reputation: 3045

You can make an object that you can assign to be the delegate

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
}

Upvotes: 1

Related Questions