2
\$\begingroup\$

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) -> Int {
 return 3
 }
 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> 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) -> 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?

t3chb0t
44.6k9 gold badges84 silver badges190 bronze badges
asked Jun 22, 2018 at 7:27
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

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) -> 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) -> 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.

Toby Speight
87.1k14 gold badges104 silver badges322 bronze badges
answered Jun 22, 2018 at 9:07
\$\endgroup\$
3
  • 3
    \$\begingroup\$ Welcome to Code Review! Thanks for contributing this nice post; I hope to see more of your contributions in future here on Code Review! \$\endgroup\$ Commented Jun 22, 2018 at 9:52
  • \$\begingroup\$ Thank you!, I hope I can keep contribute the community at least a little bit! \$\endgroup\$ Commented Jun 22, 2018 at 9:55
  • \$\begingroup\$ @thxou Thank you very much for your answer. I will think about my implementation. Hoping there are some more answers providing different solutions maybe :) \$\endgroup\$ Commented Jun 22, 2018 at 11:29

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.