Original Author: Tiffany Pan

Table of Contents

What is it?

An UITabBarController is most commonly used to create the tab switching functionality when developing in UIKit.

class UITabBarController : UIViewController

@MainActorsimply indicates and enforces that this View Controller performs its actions on the main thread. This means that any UI updates made to our tab view controller (tapping on a tab) will always be updated on the main thread. See more about concurrency in Concurrency.

No, but what is it really?

At its core, an UITabBarController is simply a container view controller that allows the user to select between designated child view controllers to display. The selection is done via tab icons that we all know and love, namely something like

How are the views set up?

Under the hood, the actual view of a tab bar controller (when displaying a piece of content) is simply a container that holds 2 things:

  1. The actual tab bar view

  2. The view that contains your designated custom content

The tab bar view allows for the selection controls and can contain one or more tab items. The custom view contains what you designate as the root view for the currently selected tab. The image above demonstrates how the views are combine to create a cohesive tab bar interface.

Why use one?

Developers generally tend to use tab views for myriad of things, such as displaying a bunch of different functionalities and presenting information in different ways. In any case, the important thing to note is that an UITabBarController allows you to manage completely different interfaces in each tab - i.e. each tab can hold completely different views.

A TabBarController is powerful because it handles the tab switching for you - you only need to specify the specific root views for each tab by instatiating an UITabBarItem and it handles the rest of the logic, including updating the UI when the user taps on a tab. Let's dive more into how we can set one up.

How can I set one up?

Assuming you have a few root views set up (not built out is fine, but as long as the UIViewController classes have at least all been created) that you want to embed as "tabs" in your application. In this case, let's use the Spotify example I snipped earlier for ours. Spotify contains 3 tabs: a home page, a search page, and lastly a library one.

Let's first define this home page, as we would with any View Controller we create. You'd do the same with the search and library one.

import UIKit

class HomeViewController: UIViewController {

    override viewDidLoad() {
        // I like to use other colors when testing
        // to make tab-switching very obvious.
        view.backgroundColor = .systemRed
        ... // Set up this view.

Then, let's define our UITabBarController in a new file. Remember, this class acts as the container view that controls the selection of tabs.

import UIKit

class TabViewController: UITabBarController {
    override func viewDidLoad() {

To create tab bar icons and set up our views, there are a few steps. We can define a function to do so.

// MARK: - Setup Tabs
private func setupTabs() {

    // Instantiate view controllers
    let homeVC = HomeViewController()
    let searchVC = SearchViewController()
    let libraryVC = LibraryViewController() // ... etc...
    // Customize the tab items. You can insert any image here, using
    // UIImage(named: ...)
    homeVC.tabBarItem = UITabBarItem(title: "Home", image:     UIImage(systemName: "house"), tag: 0)
    searchVC.tabBarItem = UITabBarItem(title: "Search", image: UIImage(systemName: "magnifyingglass"), tag: 1)
    libraryVC.tabBarItem = UITabBarItem(title: "Library", image: UIImage(systemName: "books.vertical"), tag: 2)
    // ... Set up other tabs ...
    // Set the UITabBarController's View Controllers
    self.setViewControllers([homeVC, searchVC], animated: True)

We can then call this function in the viewDidLoad()of our TabViewController class.

override func viewDidLoad() {

The basic functionality of a tab view controller is all set up! Now, you can simply create and use it as you would with any other ViewController: TabViewController(). If you'd like it to be first thing the user sees when opening the app, you can modify the SceneDelegate.swift file to set it as the app's root view controller like so, which follows Xcode Project Setup.

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
     //... Other scene set up code ...
     let rootVC = TabViewController()
     let navController = UINavigationController(rootViewController:                 rootVC)
     /// ... Other scene set up code ...

If you want a certain tab to be the "main" tab (i.e. the one that the tab view opens on), you can do so via the tab view's .selectedIndex property.

private func setupViews() {
    /// ... Other code ...
    // Designate the initial index. 0 refers to the first tab. 
    selectedIndex = 0 

Last updated