title: Reusing UIViewController (with UITableView) for Master/Detail View Controller in Master-Detail Application?
body: <p>I am using this <a href="https://www.raywenderlich.com/472-uisearchcontroller-tutorial-getting-started" rel="nofollow noreferrer">Ray Wenderlich tutorial</a> as a guide for a project I am working on. However, I am trying to expand this template to incorporate sub-directories, sub-sub directories, sub-sub-sub directories, and so forth.</p>
  
  <p>For example, if you the click the "Candy Cane" cell within the main/home directory screen, it will take you to a "new" view controller with table view (aka a sub-directory screen) that will show various candy cane vendors and whether their prices are expensive or cheap (this will be the subtitle for each row). See the <code>subCategory</code>... txt files down below.</p>
  
  <p>I use the words category and directory interchangably throughout this post.</p>
  
  <p>Here's the first catch. In the past, I made a project that does just this, but I did it via many storyboard and view controller files for each sub-category I navigated too. Same principle goes for moving from sub-category to sub-sub-category screens and so forth.</p>
  
  <p><strong>I AM NOT TRYING TO ADVERTISE:</strong> But specifically, the app I am working on is called <a href="https://itunes.apple.com/us/app/iengineering/id1323668534?mt=8" rel="nofollow noreferrer">iEngineering</a> and its available for free on the AppStore. Please see the library part of the app as I believe it will provide additional help with understanding my end goal. Keep in mind, the current version of the application, was built using an endless number of storyboard and view controller files that has to build each time I run the simulator in Xcode. Viewing the app screenshots that show the library feature should suffice without having to download the app.</p>
  
  <p>Here's the second catch. I also have the sub-sub-categories and so forth in this app. For example, if you click a cell in the sub-category screen that shows the list of candy cane vendors and prices, it will navigate you to a new screen (sub-sub-category) to all of the different candy canes that specific vendor sales. So in my made-up text file below, <code>subCandyCaneTextFile.txt</code>, if you were to click on the cell with label "Candy Cane King" it will take you to a screen that shows "Candy Cane King" as the navigation title, and present/load a listing (imported via reading text file) that shows all of the candy canes that Candy Cane King provides. <strong>I did not provide this and other txt files that I am considering to be sub-sub categories</strong> . I would like you all to just keep this in mind for when I ask the root/heart of my question down below.</p>
  
  <p>For THIS project, I am wanting to MOVE AWAY from using multiple storyboards with many view controllers. This is because my previous project would take ~5 to 10 minutes to compile/build every time I go to build it in the simulator. Therefore, I am attempting to read in a text file at project run-time for each new/category screen in my application. I am hoping this will give me much, much quicker run times (~10 seconds). </p>
  
  <p>In the example below, the category/main view controller presents its data by reading in the txt file <code>candyTextFile.txt</code></p>
  
  <p><strong>MY QUESTION:</strong> How can I go about (transitioning from | removing) old data and (loading | replacing) in new data for sub category screens? I thought about trying to have this be the Detail View Controller screen in the <a href="https://www.raywenderlich.com/472-uisearchcontroller-tutorial-getting-started" rel="nofollow noreferrer">Ray Wenderlich tutorial</a> tutorial; however, I am then not sure how I would navigate to a sub-sub-category screen. Therefore, I think my other option may to be reuse one view controller with UITableView (Master View Controller) over and over again. I am not sure the proper way to go about this as I am still relatively new to learning Swift and Xcode.</p>
  
  <p>Overview of <a href="https://imgur.com/a/4DrGvof" rel="nofollow noreferrer">current project via Xcode</a> for this post. </p>
  
  <p>In my MasterViewController.swift,</p>
  
  <pre><code>    import UIKit
  
      class MasterViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
  
      // MARK: - Properties
      @IBOutlet var tableView: UITableView!
      @IBOutlet var searchFooter: SearchFooter!
  
      var detailViewController: DetailViewController? = nil
  
      var candies = [Candy]()
      var filteredCandies = [Candy]()
  
      let searchController = UISearchController(searchResultsController: nil)
  
      // MARK: - View Setup
      override func viewDidLoad() {
      super.viewDidLoad()
  
      // Setup the Search Controller
      searchController.searchResultsUpdater = self
          searchController.obscuresBackgroundDuringPresentation = false
      searchController.searchBar.placeholder = "Search Candies"
      navigationItem.searchController = searchController
      definesPresentationContext = true
  
      // Setup the Scope Bar
      searchController.searchBar.scopeButtonTitles = ["All", "Chocolate","Hard", "Other"]
      searchController.searchBar.delegate = self
  
      // Setup the search footer
      tableView.tableFooterView = searchFooter
  
  
      setupArray()
  
  
  
      if let splitViewController = splitViewController {
          let controllers = splitViewController.viewControllers
          detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
      }
  
      }
  
  
      private func setupArray() {
          if let filepath = Bundle.main.path(forResource: "candyTextFile", ofType: "txt") {
              do {
                  let contents = try String(contentsOfFile: filepath)
                  let lines_separatedBy_n : [String] = contents.components(separatedBy: "\n")
                  let string = lines_separatedBy_n.map { String($0) }.joined(separator: ", ")
                  var lines_separatedBy_comma : [String] = string.components(separatedBy: ", ")
  
                  // I've put this in to remove the last bit of the file that was causing the count to be one too high.
                  // I'm guessing that's why you had something similar previously?
                  lines_separatedBy_comma.removeLast()
  
                  for (index, element) in lines_separatedBy_comma.enumerated() {
                      if index % 2 == 0 {
                          let newCategory = element
                          let newName = lines_separatedBy_comma[index + 1]
                          let newCandy = Candy(category: newCategory, name: newName)
                          candies.append(newCandy)
                      }
                  }
                  for candy in candies {
                      print("category: \(candy.category), name: \(candy.name)")
                  }
                  //("\ncandies: \(candies)")
              } catch let error as NSError {
                  print(error.localizedDescription)
              }
          }
  
              print("\ncandies: \(candies)")
  
      }
  
      override func viewWillAppear(_ animated: Bool) {
      print("splitViewController!.isCollapsed: \(splitViewController!.isCollapsed)")
  
      if splitViewController!.isCollapsed {
        if let selectionIndexPath = tableView.indexPathForSelectedRow {
          tableView.deselectRow(at: selectionIndexPath, animated: animated)
        }
      }
      super.viewWillAppear(animated)
      }
  
      override func didReceiveMemoryWarning() {
      super.didReceiveMemoryWarning()
      }
  
      // MARK: - Table View
      func numberOfSections(in tableView: UITableView) -&gt; Int {
      return 1
      }
  
      func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
      if isFiltering() {
          print("Is filtering")
          searchFooter.setIsFilteringToShow(filteredItemCount: filteredCandies.count, of: candies.count)
          return filteredCandies.count
      }
      print("Is not filtering")
      searchFooter.setNotFiltering()
      return candies.count
      }
  
      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
      let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
      let candy: Candy
      if isFiltering() {
          candy = filteredCandies[indexPath.row]
      } else {
          candy = candies[indexPath.row]
      }
      cell.textLabel!.text = candy.name
      cell.detailTextLabel!.text = candy.category
      return cell
      }
  
      // MARK: - Segues
      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
          if segue.identifier == "showDetail" {
              if let indexPath = tableView.indexPathForSelectedRow {
                  let candy: Candy
                  if isFiltering() {
                      candy = filteredCandies[indexPath.row]
                  } else {
                      candy = candies[indexPath.row]
                  }
                  let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
                  controller.detailCandy = candy
                  controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
                  controller.navigationItem.leftItemsSupplementBackButton = true
              }
          }
      }
  
      func filterContentForSearchText(_ searchText: String, scope: String = "All") {
  
  
          filteredCandies = candies.filter({
              (candy : Candy) -&gt; Bool in
          let doesCategoryMatch = (scope == "All") || (candy.category == scope)
              if searchBarIsEmpty(){
                  return doesCategoryMatch
              }else {
                  return doesCategoryMatch &amp;&amp; candy.name.lowercased().contains(searchText.lowercased())
  
              }
          })
  
          tableView.reloadData()
      }
  
  
      func searchBarIsEmpty() -&gt; Bool {
          return searchController.searchBar.text?.isEmpty ?? true
      }
  
      func isFiltering() -&gt; Bool {
          let searchBarScoperIsFiltering = searchController.searchBar.selectedScopeButtonIndex != 0
          return searchController.isActive &amp;&amp; (!searchBarIsEmpty() || searchBarScoperIsFiltering)
      }
  
  
      }
  
      extension MasterViewController: UISearchBarDelegate {
      // MARK: - UISearchBar Delegate
      func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
          filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
      }
  
      }
  
      extension MasterViewController: UISearchResultsUpdating {
      // MARK: - UISearchBar Delegate
      func updateSearchResults(for searchController: UISearchController) {
          let searchBar = searchController.searchBar
          let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
          filterContentForSearchText(searchController.searchBar.text!, scope: scope)
      }
      }
  </code></pre>
  
  <p>In candyTextFile.txt,</p>
  
  <pre><code>Chocolate, Chocolate Bar
  Chocolate, Chocolate Chip
  Chocolate, Dark Chocolate
  Hard, Lollipop
  Hard, Candy Cane
  Hard, Jaw Breaker
  Other, Caramel
  Other, Sour Chew
  Other, Gummi Bear
  Other, Candy Floss
  Chocolate, Chocolate Coin
  Chocolate, Chocolate Egg
  Other, Jelly Beans
  Other, Liquorice
  Hard, Toffee Apple
  </code></pre>
  
  <p>In subCandyCaneTextFile.txt,</p>
  
  <pre><code>Cheap, Brachs
  Expensive, Spangler
  Expensive, Bobs
  Cheap, Candy Cane King
  Expensive, Jelly Belly
  </code></pre>
  
  <p>Other, sub-category, files:</p>
  
  <p>In subDarkChocolateTextFile.txt,</p>
  
  <pre><code>Cheap, Ghirardelli
  Expensive, Dove
  Expensive, Lindt
  Cheap, Hersheys
  Expensive, Hu Dark
  </code></pre>
  
  <p>In subLollipopTextFile.txt,</p>
  
  <pre><code>Cheap, Zollipops
  Cheap, YumEarth
  Expensive, Dum Dums
  </code></pre>
  
  <p>Thank you all for your time and any guidance you all may be able to offer. I greatly appreciate it.</p>