UITableViewDataSource with different sections and SearchController I have a UIViewController holding one UITableView with 3 sections. Also this UIViewController implements UISearchResultsUpdating for searching in that UITableView. The UIViewController looks like this: 

class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchResultsUpdating {

    var searchController = UISearchController(searchResultsController: nil)

    @IBOutlet weak var tableView: UITableView!

    private struct TableViewSections {
        static let sectionOne = 0
        static let sectionTwo = 1
        static let sectionThree = 2
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.setupTableView()
        self.setupSearchController()
    }

    private func setupSearchController() {
        self.searchController.searchResultsUpdater = self
        self.searchController.dimsBackgroundDuringPresentation = false
        self.searchController.searchBar.placeholder = "Search"
        self.searchController.searchBar.autocapitalizationType = .sentences
        self.searchController.hidesNavigationBarDuringPresentation = false
        if #available(iOS 11.0, *) {
            self.navigationItem.searchController = self.searchController
        } else {
            self.tableView.tableHeaderView = self.searchController.searchBar
        }
    }

    private func setupTableView() {
        self.tableView.delegate = self
        self.tableView.dataSource = self
    }

    func numberOfSections(in tableView: UITableView) -&gt; Int {
        return 3
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {

        // In each of these cases i will do the work that is needed to return the correct number of rows
        // Just for demonstration i return a random int in every case

        if self.searchController.isActive {
            switch section {
            case TableViewSections.sectionOne:
                return 10

            case TableViewSections.sectionTwo:
                return 20

            case TableViewSections.sectionThree:
                return 30

            default:
                return 0
            }
        } else {
            switch section {
            case TableViewSections.sectionOne:
                return 15

            case TableViewSections.sectionTwo:
                return 25

            case TableViewSections.sectionThree:
                return 35

            default:
                return 0
            }
        }
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {

        // In each of these cases i will do the work that is needed to show the correct content
        // Just for demonstration i return UITableViewCell() in every case

        switch indexPath.section {
        case TableViewSections.sectionOne:

            if self.searchController.isActive {
                return UITableViewCell()
            } else {
                return UITableViewCell()
            }

        case TableViewSections.sectionTwo:

            if self.searchController.isActive {
                return UITableViewCell()
            } else {
                return UITableViewCell()
            }

        case TableViewSections.sectionThree:

            if self.searchController.isActive {
                return UITableViewCell()
            } else {
                return UITableViewCell()
            }

        default:
            return UITableViewCell()
        }
    }

    // MARK: UISearchResultsUpdating

    func updateSearchResults(for searchController: UISearchController) {
        // do the search work here...
    }
}


You can see the difference between tableView(_:numberOfRowsInSection:) and cellForRow(at:). 

My Question now is: What is recommended way to do so? Is the better solution tableView(_:numberOfRowsInSection:), cellForRow(at:) or is there even a better solution?
The numberOfRowsInSection: function looks good to me, changing this function to something better will depend on the possible logic you can apply in combination with the section parameter and your data. For example, if you have an array of dictionaries like this:

let data = [ 1: ["hola", "hey"], 2: ["adiós"] ]


The implementation of the method could be reduced to:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
    if self.searchController.isActive {
        let array = searchData[section]
        return array.count
    }
    let array = data[section]
    return array.count
}


That indeed is valid for five sections and for one millions sections.

For the cellForRowAt indexPath: function, I would put first the check for the searching status:

if self.searchController.isActive {
    // handle sections for searching
} else {
    // handle sections normaly
}


Doing it like this will allows you to, for example, group functionality shared across multiple sections. An implementation taking the example I put could be like:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
    let text = ""
    if self.searchController.isActive {
        let array = searchData[indexPath.section]
        text = array[indexPath.row]
    } else {
        let array = data[indexPath.section]
        text = array[indexPath.row]
    }

    configureCell(with: text, at: indexPath)
}


I did this because I prefer to not overload so much the implementation of the delegates. In configureCell:at: you must implement the logic needed for the creation of the cells based in sections and the data you received.

As I wrote before, the implementation of those methods will depends on the structure of your data, it could reduce or increase the amount of code you need to show the data in the intended way.