Navigation controllers

In this tutorial we cover the following topics


General information


The main tool we use to build hierarchical applications for iPhone is UINavigationController. UINavigationController is similar to UITabBarController in that it manages, and swaps in and out, multiple content views. The main difference between the two is that UINavigationController is implemented as a stack, which makes it well suited to working exactly with hierarchies.

A navigation controller maintains a stack of view controllers. When we design our navigation controller, we need to specify the very first view the user sees. That view’s controller is called the root view controller, or simply root controller, and is the base of the navigation controller’s stack of view controllers. As the user selects the next view to display, a new view controller is pushed onto the stack, and the view it controls appears. We refer to these new view controllers as subcontrollers.

While the navigation controller is really the heart and soul of many iPhone apps, when it comes to iPad apps, the navigation controller plays a more marginal role. A typical example of this is the Mail app, which features a hierarchical navigation controller to let users navigate among all their mail servers, folders, and messages. In the iPad version of Mail, the navigation controller never fills the screen, but appears either as a sidebar or a temporary view covering part of the main view.

Xcode offers a perfectly good template for creating navigation-based applications, and in practise we will use it whenever we need to create hierarchical applications. However, in this tutorial we are not going to use that template. Instead, we will construct our navigation-based application from the ground up, so we get a feel for how everything fits together.


  1. Step 1: create a new project
    Create a new project

    • Select File | New | Project…
    • Select Single View Application on the template selection sheet.
    • As the product name enter iOS Navigation Controller
    • Set the Language to Objective-C, devices pop-up button to Universal and make sure the check box labeled Use Core Data is unchecked.
  2. Step 2: replace UIViewController with UINavigationController
    We now need to create the basic navigation structure for our application. At the core of this will be a UINavigationController, which manages the stack of view controllers that a user can navigate between.

    • Select Main.storyboard.
    • Select the view controller in either the editor area or the Document Outline and delete it to leave the storyboard empty.
    • Find Navigation Controller in the Object Library and drag an instance into the editing area. Notice that we get two scenes instead of one – similarly to tab view controller in previous part. On the left is the UINavigationController itself. The UINavigationController has a connection wired to the second scene, which contains a UITableViewController/code. As you can see the table has the title Root View Controller. Table view controller seems to be resonable starting point when disply hierarchical data.

      001

      002

    • Select UINavigationController, open the Attributes Inspector, and check Is Initial View Controller in the View Controller section to make this the controller that appears when the application is launched.
  3. Step 3: replace UITableViewController with UIViewControlers
    • Delete UITableViewController.
    • Add new ViewController.
    • Control-click Navigation Controller and drag to the view controller we have just added and select root view controller from popup menu.

      003

      004

      005

      Notice that view controller which has been added is also equipped with Navigation item to perform correct navigation to/from other views.

    • Select ViewController.h in the Project Navigator.
    • In the editor area double-click the class name after @interface and then right-click it.
    • In the menu that appears, select Refactor | Rename….
    • The dialog should appear – make sure that option Rename related files is checked and change the view controller name to RootController.
    • Press Preview button and next Save.
    • Single-click the yellow View Controller icon in the row of icons at the top of the View Controller Scene. Next press Alt+Command+3 to bring up the Identity Inspector. In the Custom Class section as Class select ViewController.

      006

    • Open ViewController.m file and add/modify
      - (void)viewDidLoad {
          [super viewDidLoad];
          // Do any additional setup after loading the view, typically from a nib.
          self.navigationItem.title = @"Root View";
      }
      
    • When executed, Root View title should be visible on a screen

      007

  4. Step 4: add first nonroot view controller
    • In the Project Navigator, right-click the iOS Navigation Controller group and select New File….
    • Choose Cocoa Touch Class from the iOS Source section in the template dialog and then press Next.
    • Name the new class FirstViewController, make it a subclass of UIViewController. Because we are going to add this controller to the storyboard later manually, so make sure that the Also create XIB file check box is not checked.
    • Press Next and then press Create to save the files for the new view controller.
    • Find View Controller in the Object Library and drag an instance into the editing area.

      008

    • Single-click the yellow View Controller icon in the row of icons at the top of the View Controller Scene. Next press Alt+Command+3 to bring up the Identity Inspector. In the Custom Class section as Class select FirstViewController.

      009

    • Now we have two options:

      1. First: Single-click the yellow View Controller icon in the row of icons at the top of the Root Controller Scene and drag to the view controller we have just added and select Manual Segue | Show from popup menu.

        010

        011

      2. Second: Single-click the yellow View Controller icon in the row of icons at the top of the Root Controller Scene, press right mouse button and from popup menu drag from Triggered Segues | manual circle to the view controller we have just added and select Show from popup menu.

        012

        013

        014

        015

        016

    • Click on segue between Root Controller and First View Controler and bring up Attributes Inspector (we can use mouse or shortcut Alt+Command+4).
    • In Storyboard Segue section as Identifier type SegueFromRootToFirst

      017

    • Open FirstViewController.m file and add/modify
      - (void)viewDidLoad {
          [super viewDidLoad];
          // Do any additional setup after loading the view, typically from a nib.
          self.navigationItem.title = @"First View";
      }
      
    • Add a button to the First View Controller, set correct constraints and title Show details

      018

    • Press Show the Assistant editor button and Control-drag from the button to the Root Controller implementation

      019

      020

      021

      022

    • Open FirstViewController.m file and add/modify
      - (IBAction)buttonPressShowDetails:(UIButton *)sender {
          [self performSegueWithIdentifier:@"SegueFromRootToFirst" sender:self];
      }
      
  5. Step 5: run the application
    Now the application is ready to run.

    023

    024

    025

  6. Step 6: passing data from root view to first view
    1. Add a text field to the First View Controller and set correct constraints.
    2. Create an outlet for this text field named textFieldRoot

      026

    3. Add a property stringDataFromRoot to FirstViewController.h
      #import <UIKit/UIKit.h>
      
      @interface FirstViewController : UIViewController
      @property (strong, nonatomic) NSString *stringDataFromRoot;
      @end
      
    4. Modify viewDidLoad from FirstViewController.m file
      - (void)viewDidLoad {
          [super viewDidLoad];
          // Do any additional setup after loading the view.
          self.navigationItem.title = @"First View";
          NSLog(@"Data from Root View: >%@<", self.stringDataFromRoot);
      }
      
    5. To RootController.h add
      #import "FirstViewController.h"
      
    6. Add to RootController.m the code
      - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
          if([segue.identifier isEqualToString:@"SegueFromRootToFirst"]){
              FirstViewController *firsVC = (FirstViewController *)segue.destinationViewController;
              firsVC.stringDataFromRoot = self.textFieldRoot.text;
          }
      }
      
  7. Step 7: run the application
    Now the application is ready to run for the second time.

    027

    028

    029

    030

  8. Step 8: add programmatically a second view controller
    1. Create a new class named TempViewController as we did it in step 4.
    2. Add a buttoon Next level to the FirstViewController.
    3. Add an action buttonPressNextLevel related to this button.

      031

    4. To FirstViewController.h add
      #import "TempViewController.h"
      
    5. Add View Controller to the storyboard.
    6. Single-click the yellow View Controller icon in the row of icons at the top of the View Controller Scene we have just added. Next press Alt+Command+3 to bring up the Identity Inspector. In the Custom Class section as Class select TempViewController.

      032

    7. In storyboard, click on the Temp View Controller, click on the identity inspector and change the Storyboard ID to IDTempViewController. Also click the check that says Use Storyboard ID.

      033

    8. In FirstViewController.m add/modify
      - (IBAction)buttonPressNextLevel:(UIButton *)sender {
          TempViewController * tempVC = [self.storyboard instantiateViewControllerWithIdentifier:@"IDTempViewController"];
          tempVC.title = @"1";
          [[self navigationController] pushViewController:tempVC animated:YES];
      }
      
  9. Step 9: run the application
    Now the application is ready to run for the third time.

    034

    035

    036

  10. Step 10: add programmatically an infinite numer of view controllers
    1. Add a buttoon Next level to the TempViewController.
    2. Add an action buttonPressNextLevel related to this button.
    3. In TempViewController.m add/modify
      - (IBAction)buttonPressNextLevel:(UIButton *)sender {
          TempViewController * tempVC = [self.storyboard instantiateViewControllerWithIdentifier:@"IDTempViewController"];
          //To join NSString-s
          //[NSString stringWithFormat:@"%@/%@", one, two];
          //or
          //string1 = [string1 stringByAppendingString:string2];
          tempVC.title = [self.title stringByAppendingString: @"1"];
          [[self navigationController] pushViewController:tempVC animated:YES];
      }
      
  11. Step 11: run the application
    Now the application is ready to run for the fourth time.

    037

    038

    039

    040

    041

    042