Segues and Navigation in iOS (II): Define Segues Programmatically

May 20, 2017 in
Segues and Navigation in Swift. Push, Modals and Exit Segues. Digital Leaves. Define Segues Programmatically, pass data to destination view controllers. The Unwind Segue. Bootstrap Modal. Segues in iOS.

Welcome back! This is a series of tutorials to get you started with iOS segues and Navigation in Swift. In the previous episode, we learned how to define segues via the Interface Builder. This episode is devoted to teach you everything on how to define segues programmatically. Besides, we will learn how to pass parameters to destination view controllers.

This article assumes that you have previous experience with the Interface Builder, and creating user interfaces, outlets and actions. Otherwise, I recommend you to read the tutorial series “Your first iOS App” first.

Let’s start.


In the previous episode, you did bind a button to a segue to another view controller. As a result, whenever the button was pressed, you will transition from your current view controller to the new one. That can be enough for a lot of scenarios in your app.

However, there are multiple situations in which you would want to define segues programmatically. When I say “define” here, I don’t mean that we will create the UIStoryboardSegue object directly in code. Actually, we will usually define segues in the Storyboard via the Interface Builder. However, we will launch them programmatically.

First and foremost, this allows you to trigger the segue not only when the user presses one button, but in response to multiple events. Imagine that you have a collection view with items that can be shared. Each cell in the collection view has a “share” button at its right. Also, you can do multiple selection on the items of the collection view. Once you have selected some items, you can share them all at once by pressing a “share” button on the top bar. Imagine also that the share action triggers a new view controller with some options for sharing. The picture below shows this situation.

Indeed, this scenario happens very often. What we are doing here is reusing the same segue, but triggered from different controls.

Besides, sometimes you need to do some preparations before presenting a new view controller. Perhaps you need to change some data, or perform a visual animation. Usually, you will need to prepare some data to send to the new view controller. We will talk about this other scenario later on.

How To Define Segues Programmatically

Let’s continue where we left our project. We had defined a segue from the “Show Segue” button to a new view controller that was pushed in the navigation controller. First, remove that segue by clicking on it in Interface Builder and hitting Backspace.

Then,  like the figure above shows, hold Ctrl and click at the view controller’s icon on top. Next, drag all the way to the new view controller and drop it there while still holding the Ctrl key. A selection for the type of segue will appear. Choose a “Show” segue and, Voila! We have created a new “Show” segue. Don’t forget to enter the Attributes Inspector and give an identifier to your segue, like “pushSegue”.

Remember how when the segue originated from the button, clicking on it highlighted that button. Conversely, notice how, if you click on the segue now, the whole view controller highlights. This is an indication that the segue is associated to the whole view controller now, so it’s not performed when clicking on any button by default. We need to trigger it programmatically.

In order to do that, we will use the method performSegue:sender: from view controller. We just need to specify the name of the segue we just created. Thus, to trigger it, we will create an action from the “Show Segue” button and call that showSegueButtonPressed:. Then, we will perform the segue in the call to the action method:

@IBAction func showSegueButtonPressed(_ sender: UIButton) {
   self.performSegue(withIdentifier: "pushSegue", sender: nil)

Now, this doesn’t seem to make much of a difference from triggering the segue directly from the button. Nevertheless, we will see its

Passing Parameters To The Destination View Controller

The real power of being able to define segues programmatically is passing parameters to the destination view controller. These parameters will commonly depend on the way we triggered the segue. As an example, let’s consider the scenario we described before where you could share just a single item in a collection view or several of them at the same time. Let’s call our origin view controller GalleryViewController and our destination view controller ShareViewController.

We could define a variable called “selectedItems”, that would be an array of items. Perhaps an array of images. This will allow us to pass the selected images (be it one or more) to ShareViewController.

Just before the origin view controller transitions to the destination view controller, a call to prepareForSegue:sender: is invoked in the origin view controller. Thus, you can use that method to initialize the parameters of the destination view controller.

Preparing For the Segue

the prepareForSegue:sender: method receives a UIStoryboardSegue object and the sender control. This UIStoryboardSegue object has two important properties:

  • identifier: this is the identifier of the segue that you defined in Interface Builder. It is useful to determine which segue is being performed and act accordingly. Remember, a view controller can segue into many other view controllers.
  • destination: this property will contain the destination view controller. Use this property to access its variables and pass the parameters by setting them. Of course, the destination view controller also serves to identify the segue being performed, by knowing its destination.

Generally speaking, it’s a good practice to distinguish between destination view controllers and set their properties based on their type. Let’s see an example to define segues to two view controllers:

public class MyViewController2 {
   var somePropertyFromMyViewController2: String!

public class MyViewController3 {
   var someOtherPropertyFromMyViewController3 = [Int]()

public class MyViewController1 {
   prepare(for segue: UIStoryboardSegue, sender: Any?) {
     if let vc1 = segue.destination as? MyViewController1 {
        vc1.somePropertyFromMyViewController1 = someValueFromTheOriginVC
     else if let vc2 = segue.destination as? MyViewController2 {
        vc2.someOtherPropertyFromMyViewController2 = someOtherValue

Here, if we are segueing into a view controller whose class is MyViewController2, we will set a specific property of that view controller. Conversely, if we are segueing into a view controller of type MyViewController3, we will modify a different property, that’s only defined for this view controller.

Putting It All Together

This will be the relevant code for the GalleryViewController:

public class GalleryViewController {
   // First: define an array of items. (1)
   var selectedItems: [Item] = []

   // This is the "share button" on the topbar (2)
   @IBAction func shareSelectedItems(_ sender: UIButton) {
       self.selectedItems = collectionView.getCurrentlySelectedItems()
       self.performSegue(withIdentifier: "shareItems", sender: nil)

   // This is the method that gets called if we click in the share
   // button of just one cell of the collection view. (3)
   func shareButtonClickedForCellItem(item: Item) {
      self.selectedItems = [item]
      self.performSegue(withIdentifier: "shareItems", sender: nil)

   // We pass the parameters via the prepareForSegue:sender method (4)
   func prepare(for segue: UIStoryboardSegue, sender: Any?) {
      if let svc = segue.destination as? ShareViewController {
         share.itemsToShare = self.selectedItems

Step By Step

Let’s go through this code step by step:

  1. First, we define an array of selected items. This “Item” type is a class with the relevant data for our items that we have defined elsewhere.
  2. Secondly, we define an action for the button on the top bar. This button will share all currently selected items in the collection view. Thus, we set our selected items via a method we define called getCurrentlySelectedItems(). Then, immediately after, we call performSegue to transition to the share view controller.
  3. Besides, imagine that we have a method that gets called whenever the “individual share” button is pressed in one of the collection view’s cells. This method will set our selected items array with just the item corresponding to that cell. Then, it will also call performSegue.
  4. Finally, no matter where the segue was triggered, the prepareForSegue:sender: method will set a variable called “itemsToShare” in our ShareViewController to the value of the selected items array we set earlier.

Notice how we are always properly setting the selectedItems variable before triggering the segue in both occasions.  This guarantees that it will have a value when the view controller finally appears.

Our Destination View Controller

Our destination view controller only needs to define a public variable that will be accessed in the origin view controller’s prepareForSegue:sender: method:

public class ShareViewController {
   var itemsToShare: [Item]()

Thus, those items will be set when this view controller needs to access them.

About The Life Cycle Of View Controllers During Segues

So how exactly does this prepareForSegue:sender: method fits in both view controllers’ lifecycles?

The following figure shows an scheme of the timeline for the two view controllers involved in a segue:

Digital Leaves. Define Segues Programmatically. Segue and View Controllers Life Cycle.The order of the last steps might vary slightly. However, what never changes is that prepareForSegue: is always called after the destination view controller has been initialized, and just before its viewDidLoad method is invoked.

Why is this important? Because if you are defining a property of the destination view controller, you will only be able to use it from viewDidLoad, not before. Thus, generally speaking, you can use a property passed through a segue in viewDidLoad, viewWillAppear and viewDidAppear safely.

Handling Modal Segues Programmatically

Let’s learn now how to launch a new view controller programmatically without having to define segues in Interface Builder. First, we need to add a view controller and design it, adding all the necessary controls.

With the design in place, we need to set a storyboard identifier for our view controller. This identifier will allow us to instantiate the view controller in code later.

Click on the view controller’s icon on the top bar. Now go to the “Identity Inspector” (third icon in the Utilities Panel)  and set the identifier in the “storyboard ID” field. I usually use the name of the class as storyboard ID, but you can use any name you like.

Digital Leaves. Define Segues Programmatically. Segue and View Controllers Life Cycle.
Showing The Modal Segue

Once we have defined an storyboard ID, we will use UIStoryboard’s method instantiateViewControler(withIdentifier:), using the identifier we did set earlier. This method will retrieve and instantiate the view controller from the storyboard. The storyboard itself is also instantiated by name, and usually, that name will be “Main” (from the Main.storyboard file)

Then, we just call present(viewController:animated:completion:) to actually segue to the modal view controller.

The animated property indicates if you want the transition to be animated, which is usually what you want. The completion property is a block that will be executed when the segue is complete and the animations have finished.

public class OriginViewController {
   @IBAction func showAModalViewController(_ sender: Any?) {
      if let mvc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ModalViewController") as? ModalViewController {
         self.present(mvc, animated: true, completion: nil)

Dismissing The Show Segue

In order to dismiss the modal view controller and get back to the presenting view controller, we call dismiss(animated:completion) on the presenting view controller. It can be accessed from the presented view controller via the “presentingViewController” optional property.

Let’s suppose we have a button in our modal view controller that closes it. We will define an action called “closeThisViewController” to call dismiss on our presenting view controller:

public class ModalViewController {
   @IBAction func closeThisViewController(_ sender: Any?) {
      self.presentingViewController?.dismiss(animated: true, completion: nil)

In essence, it’s easy to show and dismiss view controllers modally by using some methods from storyboard and view controller.

Handling Show Segues Programmatically

Finally, let’s see how to perform “Show” (a.k.a: “Push”) segues programmatically. In order to do this, we will need to have our view controller embedded in a navigation controller.

Given that situation, we can access the “navigationController” optional property of our view controller programmatically. This property access the navigation controller, and has two relevant methods:

  • pushViewController(vc:animated:): pushes a view controller in the navigation controller’s stack, effectively performing a “Show” segue to that view controller.
  • popViewController(animated:): pops a view controller from the navigation controller’s stack, thus, getting back to the previous view controller. This is the equivalent of clicking on the “Back” arrow, in code.

Showing the Show Segue

Thus, in order to programmatically perform a “Show” segue, perhaps in response to a button press, we do the following:

public class OriginViewController {
   @IBAction func segueToPushViewController(_ sender: UIButton) {
      self.navigationController?.pushViewController(destinationViewController, animated: true)

Dismissing The Show Segue

Conversely, in the destination view controller, we can get back programmatically to our origin view controller:

public class DestinationViewController {
   @IBAction func goBackToOriginViewController(_ sender: UIButton) {
      self.navigationController?.popViewController(animated: true)

By all means, if you define segues programmatically, specially for “Show” segues, make sure that the interactions make sense, UI/UX wise.

Where To Go Next

In this episode of the “Segues and Navigation in iOS” tutorial series, we learned how to define segues programmatically. We also saw how to pass parameters from one view controller to another via the prepareForSegue:sender: method.

In the next episode of the series, you will learn how to present a view controller like a bootstrap modal.

As always, you can download the code from my Github repository.