How to cleanly hide a UITableView Section

Take any app.

Go to Settings.

There’s a pretty good chance you’ll find a UITableView with grouped sections.

Most apps are built with at least one UITableView subclass, and there’s often a need to show / hide a specific section based on user settings or access to features.

We don’t get isHidden out of the box

UITableView, which is a subclass of UIScrollView and has been around since iOS 2.0, doesn’t come with a handy isHidden property, so the logic has to be handled in the datasource and delegate. This can get spaghetti-like very quickly as the logic spans across the protocol implementation and if else statements are scattered throughout the required and optional methods.

Minimize code complexity

It’s tempting to handle each specific case and set numberOfSections to n when showing the section, and n-1 when hiding the section, but this gets complicated when we have to handle the individual cell logic in cellForRowAt indexPath and in subsequent setup. There are over 40 datasource and delegate methods to keep track of, and code maintenance can get tricky from here.

There’s a better way.

The solution

Let’s start withnumberOfRowsInSection and return 0 for Section to Hide. This is a good start, but we’ll still end up with an empty section that takes up space as a result of the header / footer padding.

Adjust for layout

To adjust for the extra spacing, we can override the delegate method heightForHeaderInSection and return CGFloat.leastNonzeroMagnitude for our hidden section.* Note that returning 0 here will not work; there must be a value for the height.

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
  return shouldHideSection ? CGFloat.leastNonzeroMagnitude : 20
}

If you’re already overriding titleForHeaderInSection, you’ll also need to set the section title to nil.

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
  return shouldHideSection ? nil : "Section Title"
}

*You may also need to override heightForFooterInSection or set the footer value to < 1 in the storyboard.