A natural place to start out with Swift and Xcode is to build Single View Applications. This is a great template that Xcode provides and is a great starting point for almost every project. But as you grow your applications you begin to need more than one screen or view and hence more than one view controller. Most applications, except the most basic, consist of more than one view controller and it is your job as an iOS developer to manage the communication between your multiple view controllers to create your app's UX workflow. In this post I will cover how to add multiple view controllers to a Swift iOS app, how to transition from one view controller to another using navigation controllers and segues, and how to pass data from one view controller to another.
I will be using a clean code demo project available on github that you can use as a reference to follow along the step-by-step.
0. Start a new Single View Application so that you have a starting point.
Name your project and set the project options.
After choosing a place to save your project you will have your starting point: an app that has a single view. The classic "Hello, World" tutorial would have you place a UILabel on that View. Run the App and see it in the Simulator of your choice to make sure everything works.
(This is my Initial Commit in the github sample project).
1. With your brand new, shiny, Single View App go to the Main.storyboard and drag out a View Controller from the Utility Object Library and place it next to the template provided View Controller in the Storyboard.
As in the original Scene or View drag a UILabel onto the Second Scene or View. I just used a label with the text "Second View Controller."
The original View Controller that Xcode provided is backed by the ViewController.swift file which you can validate by looking at the Utilities Panel Identity Inspector and looking at the Class. We will need to make a new View Controller class for our second View Controller that we just dragged onto the Storyboard. Do this by selecting from the menu bar: File > New File > and then selecting Cocoa Touch Class.
Then in the next dialog box you can name your class. I chose to call it simply SecondViewController.swift. Notice the naming convention of capitalized camel case since this is a Class and not a property. Properties are traditionally non-capitalized camel case.
After selecting where to save the file, I chose to save it in the same folder as the first ViewController.swift, you need to go back to the main.storyboard and make sure you select your dragged in View Controller and in the Utilities Panel Identity Inspector you pick this new SecondViewController.swift class.
You can now select the custom class file from the File Navigator and examine what Xcode created and review what you have: a UIKit import at the top and our custom class class that inherits from UIViewController. We also have a couple of function overrides (viewDidLoad, didReceiveMemoryWarning, and a commented out prepareForSegue function).
At this point we have an app with multiple view controllers and multiple views but there is no connection between the original and second view controller. It will compile and run but with a warning of "Scene is unreachable due to lack of entry point and does not have an identifier for runtime access..." Pretty spot on as far as warnings go. The Scene is our dragged View Controller in the Storyboard and it is indeed unreachable at this stage.
(This is my "Added a Second View Controller" github commit.)
2. Transitioning from one view to another is achieved with a segue. Let's add a button onto the original, first, view controller such that when the user taps it the App will segue from the first scene to the second scene. Once you have the button on the View then control-drag from the button to the second view controller and then select which type of segue action you'd like. I chose "Action Segue."
In the Storyboard select the segue and in the Utilities Pane Attributes Inspector give the Segue an Identifier. I chose "showSecondViewController".
If you run the app now you can tap the button on the first scene and segue to the second scene. One problem with this transition is that its one way - you can't go back to the first scene. Let's fix this by adding a Navigation Controller.
(This is my "Added a Segue between scenes" github commit.)
3. A Navigation bar lives inside a Navigation Controller. Adding one to your app is easily done by selecting the first scene in the storyboard and from the Editor Menu item select Editor > Embed in > Navigation Controller.
This puts a new scene in front of the original first scene which is the Navigation Controller.
If you run the app now you will notice that there is now a new bar under the status bar that was not there before and you can continue to tap the button on the first scene and segue to the second scene. But now you get a Back Bar Button Item in the Navigation Bar and you can go back to the first scene. Now we have a starting point to start passing objects from one view controller to another.
4. Remember in the first step we put a label in the Second Scene in the Storyboard. To demonstrate passing data from one view controller to another let's pass a string from the First View Controller to the Second View Controller such that this label in the Second View Controller will say whatever the first one passes it.
First, in order for the Second View Controller to be able to update the label we'll need to have an Outlet to that UILabel. We do this with the Assistant Editor and Control dragging from the Label to the SecondViewController.swift file.
We'll also need a property such that the first view controller can set right before the transition or segue. Add the following code for the property (my line 14 which I called status) and in the viewDidLoad() function add the assignment of that property to our label through our outlet (my line 18).
If you run the app now you'll see that when you tap the button and segue to the second scene the label is gone. In fact it is the empty string we assigned as a default which demonstrates the View Controller has set it thereby erasing what was in the storyboard. Next we'll pass a value from the first view controller to the second using this property.
5. Remember how in step 2 we named the segue "showSecondViewController." That is going to come in handy as we check for that in the first ViewController.swift file in a new prepareForSegue() function that we'll add.
This function is called right before the transition and as such the segue knows the destination view controller. This is where we can set properties of the destination view controller right before we segue to them. Here we are setting the status string property to "Hello, World."
If you run the app now you'll see that when you tap the button in the first view controller the second view controller's label is set to this String of "Hello, World."
(This is my "Added prepareForSegue in View Controller" github commit.)
And that's it
If you've followed along this far you now have added multiple view controllers to a Single View Swift iOS app, you know how to transition from one view controller to another using navigation controllers and segues, and you know how to pass data from one view controller to another.
Where to next?
To enhance your understanding of View Controllers treat yourself to Bruce Nilo's Session 214 from WWDC 2014 entitled View Controller Advancements in iOS 8.
Now go off and add multiple view controllers to your next killer Swift app.