Swift 3 segues, unwind segues, storyboards, and view/navigation controllers

[Download Xcode 8.2.1 project with full Swift 3 source from GitHub.]

Today’s tutorial covers transitions — segues — from one source storyboard scene to another destination scene, and unwind segues leading back from destination to source… I created a project to help you follow along with this tutorial, written in Swift 3, against the iOS 10 SDK, and using the Xcode 8.2.1 IDE. Please download the project. The app produced by the project is shown in action in the following video. Please watch before continuing on:

Segues don’t exist in a vacuum. I’ve introduced a UINavigationController into the mix. Of course, you’ll see a few UIViewControllers. I’ve also used a UITableView and managed its complexity by breaking it into logical pieces by using Swift “extensions.” As you proceed, you’ll have to grasp concepts like Auto Layout and managing a table view’s data source.


While reading this tutorial, you may ask, “Where’s the code for unwind segues?” Don’t worry. It’s toward the end of this article. The UINavigationController provides “unwinding” via its “back” button functionality. I will show you an example of an explicit unwind segue — toward the end of this post.

Introduction


Let’s talk about the prerequisite concepts you need to learn or review before diving into building an app which highlights segues. From Apple:

Use segues to define the flow of your app’s interface. A segue defines a transition between two view controllers in your app’s storyboard file. The starting point of a segue is the button, table row, or gesture recognizer that initiates the segue. The end point of a segue is the view controller you want to display. A segue always presents a new view controller, but you can also use an unwind segue to dismiss a view controller. …

You do not need to trigger segues programmatically. At runtime, UIKit loads the segues associated with a view controller and connects them to the corresponding elements. When the user interacts with the element, UIKit loads the appropriate view controller, notifies your app that the segue is about to occur, and executes the transition. You can use the notifications sent by UIKit to pass data to the new view controller or prevent the segue from happening altogether.

What is a storyboard? What UIKit controllers can be used as storyboard scenes?


Storyboards are a great visual aid in terms of organizing your app, and Interface Builder is a great tool for designing complex and elegant user experiences.

In the movie making industry, storyboards are used to plan out all the individual scenes, show the sequence of the scenes, and show the relationships between scenes, i.e., “the movie starts at scene 1, then we perform scene 2, then we perform scene 3…” Storyboards are generally drawn out by hand on large pieces of paper or poster board. They define the actors required in each scene, and the actions and dialogue by/between the actors. It’s quite the same in an iOS app. Think of the actors as buttons, views, sliders, text fields, and think of the transition leading from one scene to another as a segue. According to Apple:

A complete iOS app is composed of multiple views through which the user navigates. The relationships between these views [view controllers or scenes] are defined by storyboards, which show a complete view of your app’s flow. Interface Builder’s storyboard designer makes it easy to create and design new views, and chain them together to create a complete user interface that’s ready for your custom code.

Xcode includes storyboard controllers [scenes] for:

  • Table View Controller
  • Collection View Controller
  • Navigation Controller
  • Tab Bar Controller
  • Page View Controller
  • GLKit View Controller
  • Or build your own

What is a storyboard scene? What is a UIViewController in a storyboard scene?


A scene, just like in the movies, should be a finite, well-defined unit of meaning, visual display, actors, interactions between actors, and functionality. Take our storyboard scene for animating a UIView from a previous post. The scene itself is a UIViewController. The actors are two UIView’s and a UIButton. The interactions/functionality: pressing the UIButton causes a new red UIView to be programmatically added to the big blue UIView, and then the red UIView animates.

What is a UIViewController in code? What is the backing UIViewController subclass for a UIViewController in a storyboard scene?


Dragging a UIViewController, UITableViewController, or UICollectionViewController (scene) into a storyboard is a start, but won’t get you too far. In order for that UIViewController/scene to become active in your movie/app, you need to create what’s often called a “backing” UIViewController (subclass) in code for your storyboard UIViewController. Then you can connect actors in your scene into code via IBOutlets and access the actors’ properties, like color, size, text, width, and height. You can also connect actors in your scene into code via IBActions and make the actors do things.

What is a navigation controller?


Again, from Apple:

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. …

A navigation controller’s primary job is to manage the presentation of your content view controllers, and it is also responsible for presenting some custom views of its own. Specifically, it presents a navigation bar, which contains a back button and some buttons you can customize. A navigation controller can also optionally present a navigation toolbar view and populate it with custom buttons.

Building the sample app to demonstrate segues


Let’s create a new Xcode project, configure the user interface in the storyboard, and encode our logic in Swift 3.

Creating the project and performing initial storyboard configuration


1) Open up Xcode 8.x and create a new iOS app based on the Single View Application template.

2) Go into Interface Builder.

3) Drag a new UIViewController from the Object Library onto your storyboard. Place it immediately to the right of the default view controller that was added when you first created your project.

Note: Steps 4, 5, 6, 7, 8, 9, 10, and 11 are demonstrated in the following video, so please watch:

4) Select your app’s entry point view controller — the one with the arrow pointing into it. That’s the UIViewController which is displayed when your app first starts. (If you look at the Attributes Inspector for that UIViewController, you’ll see that it is marked “Is Initial View Controller.”)

5) With the Initial View Controller selected, go to the Xcode menu system and select Editor -> Embed In -> Navigation Controller. A “Navigation Controller” scene will appear and will shove your Initial View Controller and other view controller over to the right. The Navigation Controller now becomes the Initial View Controller.

6) Go to the Object Library’s “Filter” text box and type in the word “table.” Your Object Library choices will be narrowed down to three UITableView-related objects. Click on the “Table View” object and drag it onto your first view controller (the one you embedded in a navigation controller in step 5).

7) Resize the new UITableView to fill the entire surface area of your first view controller.

8) Select the new UITableView. Use the Auto Layout “Add New Constraints” (formerly “Pin”) button (looks like |-[]-|) and add four “Spacing to nearest neighbor” constraints with constant zero to the table view.

9) In the Attributes Inspector for the table view, change “Prototype Cells” from zero to one. An object labelled “Prototype Cells” will appear at the top of your table view.

10 Select the prototype cell by clicking on the blue rectangle directly under the “Prototype Cells” label. Go to the Attribute Inspector for this Table View Cell and type the word “cell” into the Identifier text box. Prototype cells must have a “reuse identifier.” You can read about it here.

11) Are you ready for some segue action?! [control]-click from the table view’s prototype cell and drag to the body of the view controller on the right side of the storyboard. A black context menu will appear. Under “Selection Segue,” select “Show.” You’ve just created your first segue. The segue will show up as a fancy arrow pointing from the view controller containing the UITableView to the view controller on the storyboard’s right side. See Figure 1 below.

This tells the iOS runtime that whenever a user taps on a table view cell, they should navigate to the view controller on the storyboard’s right side.

12) Segues should generally be assigned a unique identifier. Click on the segue (arrow) you just created, select the Attributes Inspector, and type “tableViewCellTap” into the Identifier text box, as shown in Figure 1 below (click to enlarge):

Figure 1. Set the segue ID.

Writing the app’s Swift 3 code


Now we’re going to write some Swift 3 code. I’ve organized the process into several sections so that you can follow my design and coding. Once again, I urge you to download the project which contains all the code discussed herein.

Encoding the view controller to which we segue

First we need to add a new UIViewController subclass — a backing class for the view controller to the right of the first view controller containing the table view. This is the view controller that we segue to when table view cells are tapped.

1) Highlight the yellow “Segues and Unwind Segues in Swift 3” virtual directory in Xcode’s Project Navigator, [control]-click, and select New File…

2) In the dialog that opens, choose the iOS “Cocoa Touch Class” template and click the Next button. See Figure 2 below:

Figure 2. Choose detail view controller template.

3) Name the new class “DetailViewController,” make it a subclass of UIViewController, set the language to Swift, click Next and then save the file. See Figure 3 below:

Figure 3. Subclass the DetailViewController.

4) Set the new DetailViewController as the backing class for its corresponding storyboard scene (the one on the right of the first view controller containing the table view). See Figure 4 below.


5) Add two labels to the view controller (the one on the right of the first view controller containing the table view). Set Auto Layout constraints on the two labels. See Figure 4 below.

Figure 4. Set the DetailViewController’s backing code/class.

6) Create an IBOutlet from the bottom label in the DetailViewController scene to its corresponding subclass as shown in the following video:

Configuring the table view and segue

We’ll wire up a working table view with two sections. We’ll use UIKit’s segue management API functions to allow our segue for the first table view section’s rows. To show you the power of segues, we’ll “prevent the segue from happening altogether” in the table view second section’s row. Y’all can read my code and figure out what I’m doing with the table view in my first view controller. I’ve written some clean inline code commentary to answer why I’m writing certain code.

Segue details

While reading my code, pay special attention to these two UIKit API methods:

You’ll find yourself using the “prepare” method quite often. By using a UINavigationController, I’ve created an example of a master-detail, information drill-down hierarchical interface. For example, the rows in the first section in my UITableView could contain the names of pop singers. Each time you tap on a singer’s name, you segue to a screen that could show all sorts of details about that person (a photo, a biography, date of birth, discography). So each time a user taps on a singer’s name, you as the developer need an opportunity to gather all the details about that singer before you segue to the detail screen — “singer profile” if you like.

In my simple example, I use “prepare” to get the text from the cell that was tapped and pass its value to DetailViewController.

The “shouldPerformSegue” method gives me fine-grained control over which UITableViewCells cause a segue and which don’t. I’m sure you’ve seen apps in which a UITableView’s bottom section had cells with text like “About” or “Contact Us.” What I’ve done with “shouldPerformSegue” is to prevent a segue when the cell containing the text “Non Segue 1” is tapped. I could have configured that cell to open a URL for a contact form in Safari. In this case, I’m just writing to the console, but you catch my drift, eh, what?

I’m now going to show you all the custom code I wrote to make this app work. Be sure to read the section entitled “General segues” below my source code. Remember that I will show you an example of an explicit unwind segue in the “General segues” section.

Swift 3 code


Here’s my Swift 3 code for the first view controller (ViewController) and the DetailViewController:

General segues


To show you an example of an explicit unwind segue, I took the following steps:

1) Added another UIViewController scene to the storyboard just to the right of the DetailViewController scene. I gave it the title “Detail Detail VC” to emphasize the fact that it represents yet another segue to the right.

2) Added a button with text “Close” to the “Detail Detail VC” UIViewController scene and set Auto Layout constraints on the button.

3) Added a button entitled “Segue to Next Screen” to the DetailViewController scene and set Auto Layout constraints on the button.

4) [control]-dragged to create a “Show” type segue from the “Segue to Next Screen” button to the new “Detail Detail VC” UIViewController scene. Gave the segue a unique identifier.

5) Created an IBAction to represent an unwind segue in DetailViewController. You can see the highlighted lines 31, 32, 33, 34, 35, 36 in DetailViewController’s source code above, but here it is again:

6) [control]-dragged from the “Close” button on the “Detail Detail VC” UIViewController to the scene’s “Exit” icon (). I made sure that the black “Action Segue” context menu came up listing the “unwindSeguefromDetailDetail” method (the unwind segue’s IBAction in DetailViewController). I made sure the blue line I dragged from the “Close” button connected with “unwindSeguefromDetailDetail:” on the context menu.

Steps 4 and 6 above are shown in the following video:

With little effort, I was able to 1) create a transition — segue — from the DetailViewController to the “Detail Detail VC” UIViewController, and 2) create a transition — unwind segue — from the “Detail Detail VC” UIViewController scene back to the DetailViewController scene. In simpler terms, I enabled the user to open a new screen with a button tap, close the new screen, and return to the place where it all started.

Note that I could’ve skipped the “Close” button step and leveraged the UINavigationController’s “back” button feature so that the user could return from the “Detail Detail VC” UIViewController scene back to the DetailViewController scene. Note that logically you almost never would encode an unwind segue when you could just pop the current view controller off the stack to return to the source scene.

But my unwind code is technically valid, despite the presence of a UINavigationController. I wanted to show you how to develop an explicit segue and unwind segue scenario.

You’re definitely going to find yourself in situations in which your scenes are not embedded in a UINavigationController. You’re going to want to use explicit segues and unwind segues. Segues are a great way to enable and control app flow.

I hope you enjoyed this rather lengthy tutorial. Please leave a comment if you have questions or feedback. Check back soon. Thanks!

[Download Xcode 8.2.1 project with full Swift 3 source from GitHub.]

Author: Andrew Jaffee

Avid and well-published author, software engineer, designer, and developer, now specializing in iOS mobile app development in Objective-C and Swift, but with a strong background in C#, C++, .NET, JavaScript, HTML, CSS, jQuery, SQL Server, MySQL, Oracle, Agile, Test Driven Development, Git, Continuous Integration, Responsive Web Design, blah, blah, blah ... Did I miss any fad-based catch phrases? My brain avatar was kindly provided by http://icons8.com under a Creative Commons Attribution-NoDerivs 3.0 Unported license.

1 thought on “Swift 3 segues, unwind segues, storyboards, and view/navigation controllers”

Leave a Reply

Your email address will not be published. Required fields are marked *