The UIViewController life cycle

As the requirements for our UI grow, we need to have more granular control of our views. We need to be able to tell what state our view is currently in inside our code. Is it, for example, shown or did the user just close the app? Is the app currently navigating from one view to another or is it just about to be shown, but still loading. All of these states refer to the  life cycle of the UIViewController, which is very important when we want to build a great UI. The life cycle of a view can be overwhelming to dive into, but often we only need a couple of these states in order to make our UIs as we want them to be. The way we handle these states is by implementing certain methods defined by Apple. Then, Apple guarantees to call these methods at the right moment according to the view life cycle. Let's take a look at some of the important states related to the UIViewController:

We have covered a lot of fundamental concepts related to UIs in iOS in this chapter, and it is now time to use that knowledge to create a small application. We will create an application named Starry Night, which is a simple application that will animate the background of the application based on input from the user. Specifically, the user will be able to press two buttons: Day and Night; we will animate the background based on that.

Using the same approach as explained in Chapter 11 , Simon Says, we will create a new (Single View Application) project that we name Starry Night. Remember to save the project on a place on your hard drive where you will be able to locate it again.

Next, we will open up Main.storyboard and drag two buttons onto our canvas toward the bottom.

Designing the UI

Then, we will name the button on the left Day and the button on the right Night. You can rename the button by double-clicking on the button on the canvas or using the inspector on the right side of Xcode, as can be seen in the following screenshot, where we just named our button Night:

Designing the UI

With that in place, we need to set up the Auto Layout constraints to ensure that our interface scales correctly when being run on devices with different screen sizes. Start by selecting the button with the name Day in the lower-left corner. Then, after it has been selected, click on the small square icon at the bottom:

Designing the UI

Clicking on that icon will bring up a small window that will assist us in adding some constraints.

The first part of the window that has a small square symbol with values on each side makes it easy for us to add constraints for our button, which will tell it how to be positioned in relation to its nearest neighbors in the view hierarchy. In this case, we are interested in ensuring that it will pin to the bottom and to the left, offset by 25 points. To do this, we enter 25 in the field to the left and to the bottom of the square. Note how the red lines become solid as we enter values, indicating that our constraint is now active on those sides of our view:

Designing the UI

Having pinned the button to the lower-left corner, we need to specify the size of our button. Luckily for us, Interface Builder (IB) has already filled in its current size, which should match the size of the name we added for our button. All we need to do is activate these constraints. To do this, we just check the two checkboxes for Width and Height. Lastly, we select the Items of New Constraints option for Update Frames to ensure that the position of our button will be updated on the canvas. This will make it a little easier for us to validate that the constraints we just added correspond to how we imagined the position of our button. All the constraints for the Day button should look like this:

Designing the UI

After clicking on Add Constraints, your canvas should look something like this:

Designing the UI

Now we will do the same thing for the button on the right named Night but, in this case, we will make it pin the right-hand side and the bottom of the square. This means that the constraints to add should look as follows:

Designing the UI

Note how the values for Width and Height in this case are not equal as the name of this button is longer. Then, try to run the application on an iPhone 7 and ensure that our buttons are positioned correctly toward the corners at the bottom:

Designing the UI

In order to validate that our UI scales correctly across devices with different screen sizes, let's try to run it on an iPhone 7 Plus as well. If the constraints have been set up correctly, it should look great. Our interface now scales with the size of the screen. Instead of adding extra white space on the right-hand side and at the bottom, our interface now looks similar to how we designed it for iPhone 7.

In the earlier chapters, we programmed console applications using playgrounds and in the previous chapter, we started looking at how we can use IB in Xcode to lay out views. The last but most important part is how we tie the two worlds together, that is, how do we write code that can be triggered by the click of a button? How do we update the background color of our view when something happens in our code? The glue between these two worlds is something called a View Controller, which has the  UIViewController type.

The UIViewController is a special type that can be tied together with a view (the canvas we looked at) in a storyboard. This enables our app to communicate back and forth between the view and our code. Before looking into how to do this, open up the ViewController.swift and simplify its content by removing some methods so that you end up with the following code:

import UIKit
 
class ViewController: UIViewController {
 
}

Next, we will open Main.storyboard again and then make Xcode show the Assistant editor by clicking on the icon with two circles in the top-right corner of Xcode:

Adding functionality to our interface

This should give you two vertically divided source editors. The one on the left should be the storyboard we already selected and the one on the right should automatically be the ViewController.swift file. If not, ensure that you set it to automatic at the top of the right source editor so that it selects this file automatically:

Adding functionality to our interface

Having these two views side by side, we are now able to connect the two. Press and hold Ctrl while holding the left-click on the button named Day in the canvas. Then, while holding the left-click and beginning from the button, dragging into the editor on the right-hand side in the view controller and let go when inside the class body:

Adding functionality to our interface

If done right, this should give you a small popup, which lets you define the connection we are about to make. In that popup, we will set the Connection to Action and type in dayTapped as the name of our action:

Adding functionality to our interface

After pressing Connect, Xcode should generate some code for the view controller class so that you will end up with the following:

import UIKit
 
class ViewController: UIViewController {

    @IBAction func dayTapped(_ sender: Any) {
    }
 
}

This means that when we tap on our Day button, this function, named dayTapped, will be called. We will now do the same thing for the Night button so that we end up with two functions inside our class body. Let's call the second function nightTapped and remember to set the Connection to Action. Your ViewController.swift should now look like this:

import UIKit
 
class ViewController: UIViewController {

    @IBAction func dayTapped(_ sender: Any) {
    }

    @IBAction func nightTapped(_ sender: Any) {
    }
}

Now that we have a place to put code that will be called, we can add our animation code, which will take care of animating the background when pressing the buttons. To do this, we will make a small UIView animation where we will specify the duration of the animation and the actual work involved in the animation. For our dayTapped function, we can add the following:

UIView.animate(withDuration: 1, animations: {
    self.view.backgroundColor = UIColor(red: 0.64, green: 0.83, blue: 0.93, alpha: 1)
})

In the preceding code, we say that the animation should take exactly one second to perform, and the animation itself involves changing the background color to a light blue color. We can do the same for the nightTapped button, but in this animation we will use the another UIColorUIColor(red: 0, green: 0, blue: 0.20, alpha: 1), which will give us a nice dark blue color.

ViewController.swift should now contain the following code:

import UIKit
 
class ViewController: UIViewController {

    @IBAction func dayTapped(_ sender: Any) {
        UIView.animate(withDuration: 1, animations: {
            self.view.backgroundColor = UIColor(red: 0.64, green: 0.83, blue: 0.93, alpha: 1)
        })
    }

    @IBAction func nightTapped(_ sender: Any) {
        UIView.animate(withDuration: 1, animations: {
            self.view.backgroundColor = UIColor(red: 0, green: 0, blue: 0.20, alpha: 1)
        })
    }
}

If you run the application and try to press the buttons with the labels Day and Night, you will see that it will animate between the colors we specified in our code: 

Adding functionality to our interface