UINavigationController And UITabBarController Programmatically (Swift 4)


UITabBarControllers & UINavigationControllers are the main controllers for iOS Development.They are a great way to navigate between a set of your ViewControllers. The iOS Clock app is a perfect example of using UITabBarController as the main way to control the app. There are tons of tutorials online on how to create UITabBarControllers and UINavigationControllers using interface builder, but to fully understand how they’re supposed to be used, it is good to know how to build it from the ground up programmatically.


Apple gives an awesome description.

“A navigation controller manages a stack of view controllers to provide a drill-down interface for hierarchical content. The view hierarchy of a navigation controller is self contained. It is composed of views that the navigation controller manages directly and views that are managed by content view controllers you provide. Each content view controller manages a distinct view hierarchy, and the navigation controller coordinates the navigation between these view hierarchies.”


“You use tab bar controller to organize your app into one or more distinct modes of operation. The view hierarchy of a tab bar controller is self contained. It is composed of views that the tab bar controller manages directly and views that are managed by content view controllers you provide. Each content view controller manages a distinct view hierarchy, and the tab bar controller coordinates the navigation between the view hierarchies.”

Let’s start!

(As a side note, we will create our controllers in the AppDelegate.swift for the simplicity sake. Also make sure to update the AppDelegate(window) and info.plist(delete Main.storyboard) for programmatic ViewControllers.)

1. Let’s create a Tab Bar Controller and 3 View Controllers.

Essentially, all we need to do is to create instances of our View Controllers and assign them to our Tab Bar Controller’s viewControllers property. So let’s first create a tabBarController.

let tabBarController = UITabBarController()

And then, go ahead and create three View Controllers (instances of our default ViewController). I will name them as favoritesVC, downloadsVC, historyVC and update the view’s title and backgroundColor property as orange, blue, and cyan respectively.

let favoritesVC = ViewController()
favoritesVC.title = “Favorites”
favoritesVC.view.backgroundColor = UIColor.orange
let downloadsVC = ViewController()
downloadsVC.title = “Downloads”
downloadsVC.view.backgroundColor = UIColor.blue
let historyVC = ViewController()
historyVC.title = “History”
historyVC.view.backgroundColor = UIColor.cyan

2. Create a button in our default ViewController and add a target action.

This step is optional but in order to see our viewControllers interact with navigation bar’s back button, we will add some button in our viewController. In viewDidLoad(), include the following:

let button: UIButton = UIButton(frame: CGRect(x: view.bounds.width / 2–50, y: view.bounds.height / 2, width: 100, height: 50))
button.backgroundColor = UIColor.black
button.addTarget(self, action: #selector(pushToNextVC), for: .touchUpInside)

I am placing the button in the center of our screen. Let’s add a function below the viewDidLoad() for the action.

func pushToNextVC() {
let newVC = UIViewController()
newVC.view.backgroundColor = UIColor.red
self.navigationController?.pushViewController(newVC, animated:

Here I am just creating a new view controller with a red background Color and push it to the navigation stack.

3. Set the tabBarItem for each ViewController.

Apple defines the tab bar item as follows :

“The tab bar item that represents the view controller when added to a tab bar controller.”

Since we set the title of our view Controllers already, the default value of the tab bar items will be the same as the view controller’s title.

favoritesVC.tabBarItem = UITabBarItem(tabBarSystemItem: .favorites, tag: 0)
downloadsVC.tabBarItem = UITabBarItem(tabBarSystemItem: .downloads, tag: 1)
historyVC.tabBarItem = UITabBarItem(tabBarSystemItem: .history, tag: 2)

(I am using the default system items Apple for the tabs.)

4. Set the tabBarController’s viewControllers property to an array of our three viewControllers.

let controllers = [favoritesVC, downloadsVC, historyVC]
tabBarController.viewControllers = controllers

5. Create and set a UINavigationController for each viewController.

t̶a̶b̶B̶a̶r̶C̶o̶n̶t̶r̶o̶l̶l̶e̶r̶.v̶i̶e̶w̶C̶o̶n̶t̶r̶o̶l̶l̶e̶r̶s̶ =̶ ̶c̶o̶n̶t̶r̶o̶l̶l̶e̶r̶s̶
tabBarController.viewControllers = controllers.map { UINavigationController(rootViewController: $0)}

Here we replaced our previous code with the above code. Swift’s map function allows us to create a navigation controller for each view controller and return that as an array.

Let’s run our app!

That’s it!