title: Reusable UITableViewController
body: <p>I want to avoid duplicate rewriting same code and create reusable UITableViewController.</p>
  <p>I have ExerciseViewController with 3 buttons. Each button push a UITableViewController on the navigation stack. There are three UITableViewControllers: 1) <strong>CategoryUITableVC</strong>, 2) <strong>EquipmentUITableVC</strong>, 3) <strong>MusclesUITableVC</strong>.</p>
  <p>All of these three view controllers have almost exactly same layout - cells with labels and accessory buttons. The only difference is that first view controller has got image next to title. Is it worth doing <strong>one reusable VC</strong> and instantiate it 3 times or maybe better solution create 3 separated VC (but It will be just rewriting almost same code).</p>
  <p>I use coordinator pattern.</p>
  <pre><code> class ExerciseCoordinator: NSObject, Coordinator {
       
          var childCoordinators = [Coordinator]()
          var navigationController: UINavigationController
          
          ...   
          //unnecessary code to show
          ...    
  
       // *HERE I INSTANTIATE VIEW CONTROLLERS, I PRESENT THEM MODALLY BUT I WANT TO HAVE NAVIGATION BAR, SO I NEED TO CREATE NEW NAVIGATION CONTROLLERS*
  
      lazy var equipmentVC: ReusableTableViewController = {
          let vc = AppStoryboard.Main.instantiate(ReusableTableViewController.self)
          vc.delegate = self
          return vc
      }()
      
      lazy var equipmentNavController: UINavigationController = {
          let navController = UINavigationController(rootViewController: equipmentVC)
          navController.navigationItem.largeTitleDisplayMode = .always
          return navController
      }()
      
      lazy var categoryVC: ReusableTableViewController = {
          let vc = AppStoryboard.Main.instantiate(ReusableTableViewController.self)
          vc.delegate = self
          return vc
      }()
      
      lazy var categoryNavController: UINavigationController = {
          let navController = UINavigationController(rootViewController: categoryVC)
          navController.navigationItem.largeTitleDisplayMode = .always
          return navController
      }()
  
     lazy var muscleVC: ReusableTableViewController = {
          let vc = AppStoryboard.Main.instantiate(ReusableTableViewController.self)
          vc.delegate = self
          return vc
      }()
      
      lazy var muscleNavController: UINavigationController = {
          let navController = UINavigationController(rootViewController: muscleVC)
          navController.navigationItem.largeTitleDisplayMode = .always
          return navController
      }()
  
  }
  
  extension ExerciseCoordinator: CustomExerciseDelegate {
      
      func selectCategory() {
          navigationController.viewControllers.last?.present(categoryNavController, animated: true, completion: nil)
          categoryVC.dataType = .category
      }
      
      func selectEquipment() {
          navigationController.viewControllers.last?.present(equipmentNavController, animated: true, completion: nil)
          equipmentVC.dataType = .equipment
      }
      
      func selectMuscles() {
          navigationController.viewControllers.last?.present(muscleNavController, animated: true, completion: nil)
          muscleVC.dataType = .muscle
      }
  }
  </code></pre>
  <p>I assign data type to know from where it comes from (CategoryVC/EquipmentVC/MuscleVC) when I will dismiss UITableVC.</p>
  <p>Here it is my reusable UITableViewController:</p>
  <pre><code>import UIKit
  import RealmSwift
  
  class ExerciseCategoryTableViewController: UITableViewController {
      
      var delegate: ExerciseSelectionCriteriaDelegate?
      //I use it delegate to send data back after dismiss view
      
      var dataType: DataType?
      
      var data = [String]() {
          didSet {
              DispatchQueue.main.async {
              self.tableView.reloadData() }}
          }
          
      
      override func viewDidLoad() {
          super.viewDidLoad()
          
          getData()
   
      }
      
      func getData() {
          
          if dataType == .category {
              let allCategories = RealmService.shared.realm.objects(Category.self)
              data = allCategories.compactMap({$0.category})
          } else if dataType == .equipment {
              let allEquipment = RealmService.shared.realm.objects(Equipment.self)
              data = allEquipment.compactMap({$0.equipment})
          } else {
              let allMuscles = RealmService.shared.realm.objects(Muscles.self)
              data = allMuscles.compactMap({$0.muscles})
      }
      
      
      override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
          return data.count
      }
      
      override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
  
  // below is my own shortcut for dequeue cell, it works
          let cell: ExerciseSelectionTableViewCell = tableView.dequeueResuableCell(for: indexPath)
              cell.category.text = data[indexPath.row]
          
          if let image = UIImage(named: &quot;\(data[indexPath.row].lowercased())&quot;) {
              cell.categoryImage.image = image
              cell.categoryImage.isHidden = false
          } else {
              cell.categoryImage.isHidden = true
          }
              
          return cell
      }
      
      override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
          tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
      }
      
      override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
          tableView.cellForRow(at: indexPath)?.accessoryType = .none
      }
      
      override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -&gt; CGFloat {
          return 70
      }
      
      @IBAction func closeViewController(_ sender: UIBarButtonItem) {
          closeViewController()
      }
      
      @IBAction func saveSelectedCategories(_ sender: UIBarButtonItem) {
          saveSelectedData()
      }
    
      func saveSelectedData() {
          let selectedIndexes = tableView.indexPathsForSelectedRows
          if let selectedData = selectedIndexes?.compactMap({data[$0.row]}) {
                  
                    dismiss(animated: true) {
                      
                      self.delegate?.selectedFields(for: selectedData, dataType: self.dataType)
                    }
                } else {
                    dismiss(animated: true) {
                      self.delegate?.selectedFields(for: nil, dataType: self.dataType)
                    }
                }
      }
      
      func closeViewController() {
          guard let _ = tableView.indexPathsForSelectedRows else { return dismiss(animated: true, completion: nil)}
          
          Alert.showAlertWithCompletion(on: self, with: &quot;TEXT&quot;, message: &quot;TEXT&quot;) { _ in
              self.dismiss(animated: true, completion: nil)
          }
      }
      
  }
  </code></pre>
  <p>I will be thankful if you tell me if this approach is correct or maybe better solution are separated view controllers or create protocol with default implementation?</p>