Chapter 4. View controllers, views, and outlets

This chapter covers

  • Exploring the view controller life cycle
  • Creating views
  • Modifying properties of views
  • Connecting views in the storyboard with code

Now that you’re familiar with Xcode and how to create a project, and you’ve explored Swift, the language you’ll use to build apps, you’re ready to start building an app.

In this chapter, you’ll use view controllers and views, the basic building blocks of building any app, to build two example apps:

  • You’ll build a basic “Hello World”-style interface purely in code in an app called ViewsInCode.
  • You’ll then build views into an interface in Interface Builder in a distance converter app. Using the Distance structure that you built in chapter 3, the distance converter app will convert distances from miles to kilometers.

In the next chapter, we’ll look at integrating user interaction with the distance converter app. In later chapters, we’ll look at techniques for laying out an interface. But first, we need to look a little closer at the view hierarchy.

4.1. View hierarchy

As mentioned in chapter 1, everything you can see in your app is either a view or contained within a view. Examples of views are labels, images, or plain vanilla—views! Controls such as buttons, date pickers, and switches are types of views, too.

All the views in your app could be represented in a hierarchy—views can contain other views. Right at the top of every view hierarchy of an iOS app is a special view called the window.

The window represents the entire area taken up visually by your app. You’re familiar with the concept of a window from desktop computers.

With enhancements of multitasking in iOS 9, the similarity with windows on desktop computers is even closer, because multiple apps can now be visible on the screen simultaneously. App windows no longer necessarily take up the entire dimensions of the screen. We’ll look more at the implications this has on layout in chapter 6.

Though the app window is also a type of view (subclassing UIView), it doesn’t display any content on its own. Rather, it contains another view, called its subview. Don’t get subviews confused with subclasses—a subview is a view contained in another view, while a subclass is a class that inherits its implementation from another class.

In a simple interface, an app window’s subview could be the root view for a scene. This root view would then contain subviews for every element in the interface. Subviews could be text fields, buttons, images, or other simple views. Subviews can then contain further subviews, and so on.

The distance converter app you’ll build later in the chapter will allow the user to enter a distance in miles or kilometers and perform a conversion. See figure 4.1 for the view hierarchy of the distance converter app.

Figure 4.1. View hierarchy for the distance converter scene

In the distance converter example, the app window has a subview that’s the root view for the converter scene. The root view covers the available space in the window. Underneath this root view are all the views of the scene—the text fields and labels that make up the app’s interface.

4.2. Model-view-controller

To ensure good code design in iOS, it’s highly recommended you follow the model-view-controller (MVC) design pattern. Objects in your code are conceptually divided into three broad categories: model, view, and controller. Using the MVC pattern keeps your code organized and easily manageable as you maintain or extend your app:

  • Model objects maintain the data for an application and handle any manipulation of that data. Model objects know nothing about the visuals of the scene they’re used in; they’re only interested in the data. A model object in the distance converter app could be the Distance structure that contains distance data and performs conversions.
  • As you’ve seen, views are the visual components of an app. They can also provide visual feedback on interaction and report on user interaction. They’re typically generic and reusable. Apple provides many views for you in the UIKit that are ready to go, such as labels, images, and switches. You’ve already seen that the distance converter app will contain a root view that then contains standard label and text field views.
  • Every scene contains a controller called the view controller. The view controller is a Swift object that you can customize to coordinate between the view and model objects. You could think of the view controller as the director of a scene.

The main scene of the distance converter app will be connected to a main view controller, which will coordinate between the text field views and distance data. The view controller will generate a distance model object with a default value, and use it to update the text field views with the current distance.

When you make the distance converter truly interactive in the next chapter, these text fields will notify the view controller when the user makes a change and the view controller will in turn update the distance model object.

The model in your distance converter app will only be updated by the view controller, but in certain apps it may also be updated by an external source, such as a web service. In these cases, the model should then notify the view controller of this change, so that the view controller can perform any necessary tasks, such as updating the view.

See figure 4.2 for a look at how the MVC pattern works in iOS, in relation to the distance converter app.

Figure 4.2. Model view controller in distance converter app

As you can see, in iOS, the model and view are both self-contained units. They know nothing about each other, nor do they know about the scene they’re in. The view controller contains references to the model and view objects and is in the middle of the communication between objects.

Note

If the view and model objects don’t have a reference to the view controller, how can they communicate with it? iOS has alternative solutions to solve this dilemma. In the next chapter, we’ll explore three approaches commonly used with view objects: target-action, events, and delegation (also often used with model objects). Later in the book, we’ll look at notifications and bindings, approaches more commonly used with model objects.

Let’s look more closely at the view controller and see it in operation in a sample app.

4.3. View controller

View controllers have several important responsibilities, such as

  • Responding to communication from view objects (such as from user interaction)
  • Configuring, laying out, and updating view objects for a scene
  • Responding to communication from model objects (such as from network calls)
  • Communicating with and updating the data in the model

As you’ve seen, every scene has a root view, which contains all the views in the scene, and a view controller, which is responsible for managing all the views in the scene. The view controller automatically contains a reference to the scene’s root view. Figure 4.3 shows how the view controller fits into the distance converter scene view hierarchy.

Figure 4.3. Distance converter scene

The views themselves are already built to do what they do: the label will display text, and the text field will display the software keyboard and accept user input. But it’s up to the view controller to react to your specific app’s needs.

4.3.1. Creating a custom view controller

Most of the time, the default behavior of views in a scene isn’t sufficient. Code needs to be written to customize the behavior of the scene. This custom behavior is performed by the view controller.

For example, in the completed distance converter app, the view controller will respond when the user enters a value in miles or kilometers, convert to the appropriate measurement, and display the result to the user. But how do you create a custom view controller? You can write the custom behaviors of your view controller by subclassing the UI-ViewController class and connecting this class with the scene.

Let’s put the distance converter app aside for the moment—you’ll build that later in the chapter. For now, you’ll build a basic app that displays views in code.

Create a new Single View Application Xcode project following the steps you went through in chapter 1. Call this project “ViewsInCode.” As the name suggests, the Single View Application template sets up an app with one scene created and ready to use.

Follow these steps to find where the class connected to a scene’s view controller is defined:

  1. Select the view controller for the app’s scene in Interface Builder.
  2. In the Inspector area, select the Identity Inspector (third icon).
  3. In the Custom Class field, you’ll find that this view controller is already connected to a custom class, or subclass, unimaginatively called ViewController.
  4. Because the Swift file name is usually the same as the name of the class it defines, you know to find the Swift file containing the ViewController class in the ViewController.swift file in the Project Navigator.

See figure 4.4 to help you navigate these steps.

Figure 4.4. Subclassing the view controller

Open the view controller subclass now. You can either select ViewController.swift in the Project Navigator or, for convenience, you can click the arrow next to the custom class in the Identity Inspector (see figure 4.5).

Figure 4.5. Jump to class

4.3.2. Customizing a UIViewController subclass

When you open the file, you’ll find that the ViewController class is by default prepopulated with two methods, overridden from its superclass UIViewController (see figure 4.6).

Figure 4.6. Default UIViewController

During the lifetime of a view controller, it will go through certain life events. At these special times in its life, certain view controller methods will be called. When you subclass UIViewController, you can override these methods to provide custom implementation in these moments.

You’ll see viewDidLoad and didReceiveMemoryWarning in the default ViewController subclass. You can override many more methods, and we’ll look at more shortly. But for now, viewDidLoad is a great place to start, because it’s triggered after the root view, and all of its subviews have loaded.

To prove that you automatically have access to the root view of the scene at this point, let’s change the background color of the view in code to yellow.

The variable in the view controller that references the root view has a name that’s simple enough to remember: view. You could test this out with simple code completion.

  1. In the line following super.viewDidLoad(), begin typing view. Code completion suggestions should appear automatically. With only the first two characters entered, the view property should appear as the second suggestion, with the V icon beside it indicating it’s an instance variable. (Other icons you’ll see frequently are L for local variable, S for static variable, and M for instance method.) Beside the suggestion, you’ll see that the suggested view property is an implicitly unwrapped UIView optional (UIView!). You can also see a description of the suggestion at the bottom of the suggestion window. You can scroll or use your cursor keys to explore possible suggestions. See figure 4.7.
    Figure 4.7. Code completion

  2. Select the view property from the code completion suggestions. Where does this variable come from? You definitely haven’t set up a view property in your ViewController class. The most obvious candidate is View-Controller’s immediate superclass UIViewController, but it could have come from a superclass of UIViewController. Who knows, it could even be a computed property in a protocol extension that UIViewController or one of its superclasses implements. You can find out where this property comes from by looking at the documentation. You can bring up the Help Inspector by moving the cursor inside the view in your code and selecting the help icon in the inspector panel. Curiously, the Help Inspector doesn’t tell you which class the property is declared in, so you’ll need to select Property Reference at the bottom of the property description in the Help Inspector to open documentation for this property. The documentation will indicate that this property is declared in the UIViewController class. Now that you have a reference to the root view, let’s change its background color. You know that the view property is a UIView, so you could scan through the documentation for UIView, but let’s see if you have any luck with code completion.
  3. Add a period(.) after view, and type color to see what Xcode suggests. First on the list of suggestions is a backgroundColor property—that must be it! The backgroundColor property is defined as a UIColor optional. If you look at UIColor in the documentation, you’ll find that it contains shorthand type methods that return common colors—let’s use one now to set the view’s background color.
  4. Add the following line to the viewDidLoad method after calling the super method:
    view.backgroundColor = UIColor.yellow
  5. Run the app on the simulator. You should see a blank app with a yellow background (see figure 4.8).
    Figure 4.8. Blank app with a yellow background

4.3.3. Initial view controller

Not many apps have one scene. To illustrate, let’s temporarily add a second scene to the ViewsInCode app.

  1. Open the main storyboard by selecting Main.storyboard in the Project Navigator.
  2. Drag in another view controller from the Object Library beside the other. Now, the storyboard contains two view controllers. How does the app know which scene to display first? Look closer at the left of the view controllers in the storyboard, and notice that one of them has an arrow pointing to it. Select each of the view controllers (not the view), and examine the Attributes Inspector. Notice the “Is Initial View Controller” attribute is selected for the original view controller.
  3. Select this checkbox for your new view controller. Notice the arrow now appears before that new view controller, and the storyboard entry point changes in the hierarchy too (see figure 4.9).
    Figure 4.9. Initial view controller

    You can also drag this arrow directly to the left of a view controller.
  4. Drag the arrow back to the original view controller to identify it once again as the initial view controller. When you’re finished experimenting, delete the new view controller and make sure the original view controller is set once again as the initial view controller. If there’s no initial view controller, all you’ll see when you run your app is a black screen!

iOS performs the following steps between launching your app and seeing the root view of your initial view controller:

  1. iOS instantiates the app window.
  2. iOS loads the main storyboard and instantiates its initial view controller.
  3. A reference to the initial view controller is passed to the app’s window, which keeps track of the view controller currently at the root in the rootView-Controller property.
  4. This triggers the initial view controller’s root view to be added as the window’s subview.
  5. This triggers the initial view controller to load its root view (usually from the storyboard).
  6. The window becomes visible and the root view appears.

In the end, you’ll have relationships between the app window, initial view controller, and the root view that look like figure 4.10.

Figure 4.10. Window, view, and view controllers

View controller life cycle

To know how to subclass a UIViewController object, you need to know which methods to override and when. To do this, you need to examine the steps a view controller goes through in its life cycle.

Initializing a view controller

As is the custom in any Swift type, the view controller starts off life with an initializer. The initializer doesn’t have access to the root view, so configuring the views in the scene often occurs later in the life cycle.

Loading a view

If the root view isn’t yet loaded, the view controller needs to load it. Wait—how could a root view already be loaded? Well, when one scene navigates to another scene, the originating view controller stays in memory. When returning to the originating view controller, its root view will display but doesn’t need to load again and the viewDidLoad method won’t be called.

The most common and recommended way for a view controller to load its root view is via the storyboard. However, a view controller can also get its root view in other ways. It can load its root view from a nib file (like a storyboard with one scene), or alternatively instantiate it in code by overriding the UIViewController’s loadView method.

After a root view and all of its subviews are loaded, the viewDidLoad method is called. This method is commonly overridden to perform any additional one-off setup that your root view requires. As you did earlier, you could modify the properties of the root view itself. Alternatively, you could modify the properties of its subviews, or instantiate and add new subviews to the root view.

Displaying a view

Whether the root view needed to be loaded or not, the viewWillAppear method will be called before the view displays. This method is commonly overridden if you want to update the root view or its subviews every time you navigate to this scene.

Imagine the main menu scene of a game that displays a top score field. When the user navigates to the game itself and then returns to the main menu, the top score should be updated in case the player beats it! The top score field should then probably be updated in the viewWillAppear method.

The viewDidAppear method is called after the root view is displayed. This method is commonly overridden to initiate processor-intensive work that otherwise could cause sluggishness in presenting the view. This could include starting an animation, playing a sound, or making a network call.

Removing a scene’s root view

Notice in the figure that the UIViewController’s methods for displaying its root view have companion methods for removing its root view.

For example, if your app navigates to a second scene, the root view for the first scene would disappear. Before this view is removed, the viewWillDisappear method is called. After the view is removed, the viewDidDisappear method is called. Override these methods to perform any final tidying up when the view disappears. Perhaps you want to stop a sound file, stop a perpetual animation, remove notification observers, or store a state.

Deinitializing a view controller

When any object is removed from memory in Swift, a special deinit method is called. Implement the view controller’s deinit method if you want to perform any additional cleanup right before this view controller is destroyed.

Releasing memory

One method that didn’t make the life cycle chart is didReceiveMemoryWarning. You might remember seeing this method in the autogenerated custom view controller code. With modern devices, the need to free up memory is unlikely, but if your app does have high memory expectations (for example, perhaps it’s storing many images in a cache), overriding this method is where you could free up that memory.

4.4. Managing views

Now that you know more about view controllers, let’s look at how to use a view controller to manage views. Views can be built up in code or in Interface Builder. Let’s first look at building up views in code.

4.4.1. Managing views in code

Open your ViewsInCode project again. You’ve demonstrated you had access to the view controller’s root view by editing its background color in the subclassed view controller’s viewDidLoad method.

Now that you have access to the root view, you can add subviews to it in code. Let’s add a red view that fills the width of the root view, but only half the height (see figure 4.11).

Figure 4.11. Add red view

Adding a view in code

In the ViewController class, define an implicitly unwrapped UIView object called redView above the viewDidLoad method.

var redView:UIView!

To instantiate a UIView, you need to pass in the view’s frame dimensions using a structure type called CGRect. Get the width and height of the root view with view’s bounds property. You can then set its background color to red and add it to the scene’s root view.

  1. Add the following to the end of the viewDidLoad method:
    redView = UIView(frame: CGRect(x: 0, y: 0,           1
        width: view.bounds.width,                        1
        height: view.bounds.height / 2))                 1
    redView.backgroundColor = UIColor.red                2
    view.addSubview(redView)                             3

    • 1 Instantiates view
    • 2 Ensures that the view lives up to its name
    • 3 Uses UIView’s addSubview method to add as a subview of the scene’s root view
  2. Run the app again, and you should see a red rectangle appear in the top half of the interface. Great!
Frame vs. bounds

Both the frame and bounds of a view refer to a rectangle, defined by a CGRect object that contains the size (width and height) and origin (x and y) of the view. The origin of a CGRect object usually refers to the upper-left corner.

The difference between frame and bounds is that frame is seen from the perspective of the view’s superview coordinate system, and bounds is seen from the perspective of the view’s own coordinate system. As you can see in the view in the example, the size of the bounds is often the same as the size as the frame of a view. The origin, on the other hand, often differs, depending on the perspective.

If you apply any transformations to the rectangle, however, such as scaling or rotation, the size of a view can look different from the perspective of a view’s own coordinate system or its superview’s. Scale a view 50% such as in the example, and the size of its bounds won’t change, but from the perspective of its superview, the size of its frame has shrunk by half.

We’ll explore transformations further in the next chapter.

Adding a label in code

Well, that’s all fine for basic views, but how about more complex views such as labels? Let’s add a label to the view halfway down, as in figure 4.12.

Figure 4.12. Adding a label

You can instantiate a label the same way as with a view, but using the UILabel class.

Let’s position the label halfway down the root view with 20-point margins and give it an arbitrary width and height of 20 points.

What’s the point?

Don’t worry, I’m not down in the dumps!

Points are how coordinates and distances are measured in iOS and are distinct from the actual pixels in the screen of the device. The intention of points is to have consistency of scale across different devices, especially Retina and non-Retina devices. In the main, the underlying pixels are irrelevant, and you’ll measure distances and coordinates in points.

  1. First, as before, add the definition of the implicitly unwrapped label above the viewDidLoad method:
    var label:UILabel!
    Now, instantiate the label code. Because UILabel subclasses UIView, you can use UIView properties such as backgroundColor. Give the label a temporary background color so you can see it clearly. Display text in the label with UI--Label’s text property, and use UILabel’s font property to adjust the font size.
  2. Add the following listing code after the redView code in the viewDidLoad method.
    Listing 4.1. Add label
    label = UILabel(frame:
                CGRect(x: 20, y: self.view.bounds.height / 2,
                width: 20, height: 20))
    label.backgroundColor = UIColor.orange
    view.addSubview(label)
    label.text = "Hello World"
    label.font = label.font.withSize(40)
  3. Run the app, and you’ll see a small orange rectangle appear where the text field should go. Obviously, the text field needs more space to display, but what should the width and height be? UIView has a handy method for setting the width and height to its ideal dimensions to fit its contents, called sizeToFit.
  4. Run sizeToFit on the label, and run the app again.
    label.sizeToFit()

Success! You can remove the orange background now if you like, and you should now see something similar to figure 4.12.

Checkpoint

If you’d like to compare, you can check out my project at https://github.com/iOSAppDevelopmentwithSwiftinAction/ViewsInCode.git (1.DisplayingViews branch).

You can close the ViewsInCode project; we’ll come back to it later. But now, let’s use Interface Builder to manage views in a scene in the storyboard.

4.4.2. Managing views in Interface Builder

In the remainder of this chapter, you’ll build the interface for the distance converter app that we looked at earlier in this chapter. In the next chapter, this app will convert distances the user enters, but for now you’ll specify a miles distance in code for the app to convert to kilometers and display in the text field (see figure 4.13).

Figure 4.13. Distance converter app

This time, we’ll explore building an interface using Apple’s visual tool for building interfaces, Interface Builder.

  1. First, create another Xcode project and call it “DistanceConverter.”
    Checkpoint

    If you want to skip the initial setup, you can download it from https://github.com/iOSAppDevelopmentwithSwiftinAction/DistanceConverter.git (1.InitialSetup).

  2. Click on the main storyboard in the Project Navigator to construct the interface of the initial scene. Drag on text fields and labels to make the interface you see in figure 4.14.
    Figure 4.14. Distance converter storyboard

    Earlier, you set the text and adjusted the font size of a label in code. This time, you’ll use Interface Builder’s Attribute Inspector.
  3. Select a label and find the text attribute in the Attribute Inspector. By default, it will say “Label.” Enter the text “miles,” “kilometers,” and “is equal to” for the three labels.
  4. Adjust the font size for the miles and kilometers labels. Find the font attribute and click on the arrow, to edit the font (see figure 4.15).
    Figure 4.15. Editing the font in the Attribute Inspector

    Use the custom font type if you want to specify the font family—otherwise, the default font family for a font style will be used. In iOS 9 and later, for example, the system font is San Francisco. In general, if you want a consistent look with other iOS apps, use Apple’s built-in font styles.
  5. For the miles and kilometers labels, use the built-in Title 1. You’ll use the Distance structure from the previous chapter as a model in this app.
    Tip

    When you modify the text of a label or change its font size, you might find that it’s no longer big enough to contain its content, indicated by an ellipsis (...). You can resize a view to its content by selecting a view, and then selecting Editor > Size to Fit Content. Frustratingly, you might find after running the app that Xcode has slightly misjudged the new size, and you’ll need to add a few extra pixels in Interface Builder. You can do this by dragging the width handle or adjusting the width in the Size Inspector. After resizing, you might also find you need to reposition the view.

  6. Create a Distance.swift file by selecting File > New > File, and select the Swift File template.
    Tip

    You have alternative approaches to creating a file. You could also right-click on the group in the Project Navigator where you want to create the file, select New File, and select the appropriate template. Alternatively, you could find the file template you want in the File Template library in the library area, and drag it where you want it in the Project Navigator. Too many options!

  7. Paste in the Distance structure you worked on in chapter 3. You can also find it at https://github.com/iOSAppDevelopmentwithSwiftinAction/Distance-Converter/blob/1.InitialSetup/DistanceConverter/Distance.swift.
  8. In the custom ViewController class, add a distance variable that stores a Distance object. I’m going to instantiate mine with 1,000 miles; you can instantiate yours however you like.
    var distance = Distance(miles: 1000)
    Checkpoint

    If you’d like to download the project at this point, you can check it out at https://github.com/iOSAppDevelopmentwith-Swift-inAction/DistanceConverter.git (1.InitialSetup).

Now that you have a distance object, the challenge is to display its miles property in the miles text field and its km property in the kilometers text field. As you saw earlier in the chapter, following the MVC pattern, it’s the view controller’s job to update text field views from the model.

For the view controller to update the text field views, it will need a way of referencing them in code.

Connecting views to outlets

The easiest way to get a reference to a view in the storyboard in your custom view controller class is to use what’s called an outlet. An outlet is a variable in your code that’s connected behind the scenes with a view in Interface Builder. Let’s set up outlets for the two text fields now.

Open the main storyboard. To set up your outlets, you’ll first need to open the Assistant Editor.

Using the Assistant Editor

Opening the Assistant Editor splits the editor area into two editor panes, most commonly with the standard editor on the left and the Assistant Editor on the right. The two editor panes could be the same type of editor, such as two Swift files, or they could be different types, such as the storyboard on the left and a related Swift file on the right.

Open the Assistant Editor by selecting the Assistant Editor selector at the top right—that’s the button in the middle of the three editor selectors that looks like two rings.

When you want to close the Assistant Editor, leaving only the standard editor open, select the editor selector on the left that looks like a paragraph of text.

As you’ve seen, if you select a file in the Project Navigator, the standard editor pane will open that file in the appropriate editor. How do you open a file in the Assistant Editor pane?

An alternative way to open a file in either editor pane is by using the jump bars at the top of the editor panes. The jump bars display a hierarchical path of where what you’re currently editing fits into the project. The hierarchy of the jump bars spreads on the left from the project itself, to your current location in the file on the right. Use the jump bars to jump to a different file or location within a file.

In the Assistant Editor, the left of the jump bar gives you additional modes for navigating to a file. The Manual mode gives you the same hierarchy you’ve seen in the standard editor’s jump bar. But the real magic of the Assistant Editor lies in other automated modes that open files related to your selection in the standard editor. If you have Interface Builder open in the standard editor, for example, the Automatic mode becomes available and automatically opens the source file for the object you select in Interface Builder.

If, for example, you select the view controller in the storyboard, your custom ViewController class will automatically open in the Assistant Editor pane, if you have Automatic mode selected.

Now, you should have the storyboard open in the standard editor, and the Assistant Editor open to the view controller source file.

  1. Find the text field before the label that says “miles.” Hold down the Control key and drag from the text field to your view controller source file below the declaration of distance.
  2. A connection menu appears. Give the outlet the name “milesTextField” and select Connect.
  3. A variable appears in your code. See figure 4.16 for clarification on the steps to create an outlet.
    Figure 4.16. Steps to create an outlet

You should see a line of code appear in your code defining the outlet:

@IBOutlet weak var milesTextField: UITextField!
Note

An @ symbol indicates an attribute that provides more information to the compiler about a variable or type declaration. Attributes that begin with IB indicate a possible connection in Interface Builder.

You might notice several interesting aspects of this outlet property:

  • @IBOutlet—This keyword lets Interface Builder know that this property is an outlet and can be connected to an object in the storyboard.
  • weak—The weak keyword relates to memory management and is included to prevent strong reference cycles.
    Automatic Reference Counting

    Automatic Reference Counting (ARC) is Apple’s approach to automatically removing objects from memory that are no longer being referenced. All instance variables default to be strong. While at least one strong reference to an object exists, it won’t be deallocated from memory. A weak reference to an object, on the other hand, won’t prevent an object from being deallocated from memory. Why then, doesn’t a weak IBOutlet variable get deallocated from memory? IBOutlet variables usually refer to a view in the view hierarchy, which are automatically strongly referenced in a view’s subviews array. While the variable remains in the view hierarchy of a view controller in memory, it will not be deallocated from memory.

  • Implicitly unwrapped optional— That exclamation mark at the end of the outlet declaration indicates that this is an implicitly unwrapped optional. As this outlet isn’t defined in the init() method of the view controller, it needed to be an optional, and rather than unwrapping this property every time you use it, Apple made the decision that an implicitly unwrapped optional was most convenient for outlets.
  • A circle appears to the left of the declaration, in the line number column— The filled-in circle within a circle indicates that this outlet is connected to an item in the storyboard. Hover over it to highlight the connected item in the storyboard.
Edit outlet properties

Now that you have an outlet for milesTextField, you can edit its properties, the way you did earlier when you created views in code.

  1. In the viewDidLoad() method, set the text field’s text property to the miles property of the distance object you set up earlier. As text is a String and miles is a Double, you’ll need to use string interpolation to assign the value.
    milesTextField.text = "(distance.miles)"
  2. Create an outlet for the kilometers text field as well, and this time set its text property to the km property of distance.
    kmTextField.text = "(distance.km)"
  3. Run the app.

The value for miles that you used to instantiate your distance object will be converted to kilometers and displayed in the relevant text fields.

Congratulations, you can now make connections in code to views you set up in the storyboard!

Checkpoint

If you’d like to compare your code with mine, you can check out the next branch at https://github.com/iOSAppDevelopmentwithSwiftinAction/DistanceConverter.git (2.ConvertDistanceFromCode).

In the next chapter, you’ll make this distance conversion useful by including user interaction, using the special abilities of types of views called controls.

4.5. Summary

In this chapter, you learned the following:

  • Manage your scene’s root view and subviews with a subclass of UIView-Controller.
  • Use outlets to connect views in the storyboard to variables in your code.
  • Use the Assistant Editor to create outlets. Provide custom implementation to your UIViewController subclass by overriding methods that will be called at different moments during the view controller’s lifetime. Here are several important UIViewController methods you can override:

    • init(): Initializer of view controller; view isn’t yet available.
    • viewDidLoad(): Initial setup of view here.
    • viewWillAppear(): Updates view every time you navigate to this scene.
    • viewDidAppear(): Updates view every time you navigate to this scene. Use if processor intensive, for example, to start an animation or play a sound.
    • viewWillDisappear(): Cleans up before you navigate away from this scene, for example, to stop a sound file, animation, or store a state.
    • viewDidDisappear(): Cleans up after you navigate away from this scene.
    • deinit(): Tidies up when deallocating this view controller from memory.
    • didReceiveMemoryWarning(): Place to free up memory.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset