© Radoslava Leseva Adams and Hristo Lesev 2016

Radoslava Leseva Adams and Hristo Lesev, Migrating to Swift from Flash and ActionScript, 10.1007/978-1-4842-1666-8_5

5. “Hello, Swift!”—A Tutorial for Building an iOS App

Radoslava Leseva Adams and Hristo Lesev2

(1)London, UK

(2)Kazanlak, Bulgaria

Xcode and the iOS SDK encourage you to use certain software design patterns when structuring and implementing an app. We are about to have a look at these patterns and learn how to take advantage of them. If you have fought your way through any of the theory books on design patterns1 and your first thought is “Oh, no, not another one!,” fret not. The goal of this chapter is that you learn by doing rather than by reading through pages of theory. We will make an app project and along the way cover the basics you will need for iOS app development in Xcode: from how to structure your project to how to work with storyboards and make your user interface (UI) adaptive.

In this chapter you will do the following:

  • Learn about several software design patterns: Delegation, Target-Action and Model-View-Controller (MVC).

  • Learn how to structure your apps to take full advantage of MVC.

  • Handle image assets in Xcode and create a custom view class.

  • Use Auto Layout and Size Classes to make responsive UIs for different screen sizes.

When you are done, you will have an app with an adaptive UI that will run on any iOS device. We will have it display a cute panda and let the user change the panda’s name.

Developing a Project for the iOS

In Chapter 2 we had a go at setting up, provisioning, and running an iOS app, which didn’t require a single line of code on your part. You saw how Xcode can generate and structure a working project for you and where the main tools at your disposal are. Now we will set up another app and will first spend some time dissecting the project and files that Xcode creates automatically: knowing how your project is structured will give you the best start.

Xcode mobile project anatomy

Create an iOS Single View Application project (FileNewProject, then iOSApplicationSingle View Application) and name it iOSProject. Select Swift as the language and set Devices to Universal. Click Create and let us see what Xcode has generated for us: there are a bunch of Swift files, folders, a storyboard, and resource files in Project navigator.

iOSProject

This is the root entry in the Project navigator and represents the project we have just created. It contains all source files, resources, and build settings.

iOSProject Group

All project files are organized in groups. A group is used to keep files that logically belong together, but it doesn’t have to correspond to an actual folder in the file system. You can create a new group by right-clicking inside Project navigator and selecting New Group from the pop-up menu.

AppDelegate.swift

This file contains a single class, called AppDelegate, which serves as a helper to the application and gets notified about changes in the application’s state. This class, in other words, acts as a delegate for the app, which gives it a special role. Following is a short explanation of the Delegation design pattern, which you will encounter many times in the iOS SDK.

ViewController.swift

Every screen (view) in the app is paired with a controller class. A controller supplies the view with data, responds to user actions, and is in charge of behavior when transitioning between screens. If you open ViewController.swift you will see a ViewController class already defined for you, which has a couple of methods:

  • viewDidLoad: this method is called after the view has been created and loaded on screen. Here you can add code for the initial setup of your view: show user information, for example.

  • didReceiveMemoryWarning: when called, this method gives you a chance to save any critical data and release resources when the operating system is running low on memory. Your app may get slapped on the wrist otherwise and get closed down.

Both of these methods override those in UIViewController: this class is part of the iOS SDK and is the base class that your ViewController inherits.

You can override another couple of methods of UIViewController, in order to customize what the view does just before and just after it is shown on screen:

  • viewWillAppear: here you can perform operations before the view becomes visible. For example, you can refresh the displayed data.

  • viewDidAppear: it is called when the view has just become visible. It may be a good place to notify the user if any heavy tasks are taking place, like fetching data from a server.

Main.storyboard

A storyboarddefines the app’s user interface. Everything you create with the Interface builder: every screen, control, and so on. is stored inside this file. If you open a storyboard file in a text editor you will see that it is an XML file, containing the descriptions of UI elements, transitions, and connections.

Typically there will be one main storyboard per project. However, for applications with lots of screens or for situations where workload needs to be distributed between developers you can divide the UI between several storyboards.

LaunchScreen.storyboard

This is the storyboard for your launch screen. Before iOS 8.0 this used to be a bunch of launch screen images instead.

Assets.xcassets

This is not a single file, but a resource bundle, which contains the image assets for the app. It can contain your app’s icon, launch screen, and all the images or textures that will be used in the views. In the Editor you can manage the bundle and provide different image resolutions for different screen sizes. We will see how to use image assets in the example later in this chapter.

Info.plist

This file stores the settings of your app and lists the capabilities or entitlements that the app needs, for example the capability of using cloud services. The format of the file is XML key-value pairs.

Next comes the practical part: we will add an image and will get familiar with the Model-View-Controller paradigm by creating a custom View and Controller, as well as a custom Model, which will provide data to be displayed by the View.

Using Assets

Apps often use a lot of images as part of their UI. We will see how to add and manage them.

First let us find an image that we can use in the example. If you go to pixabay.com, you can find thousands of free images under the Creative Commons license. I’m a bear lover, so I searched for “panda bear cute.” Find your equivalent to a cute panda and download it2—any JPEG or PNG will do. I renamed the downloaded file to bear.png for short and this is how I will refer to it in the steps that follow.

Let us add bear.png to the project’s assets. Click Assets.xassets in Project navigator to open the Asset Catalog editor. From there right-click inside the left panel and choose Import (Figure 5-1).

A371202_1_En_5_Fig1_HTML.jpg
Figure 5-1. Adding an image asset to the project

Find the image file using the Open dialog (Figure 5-2).

A371202_1_En_5_Fig2_HTML.jpg
Figure 5-2. Choosing an image file

This will create an image set for your image file (Figure 5-3). Importing the image also copies it in your project on disc: if you explore your project in Finder, you will find that bear.png has been put in iOSProject/Assets.xcassets/bear.imageset.

A371202_1_En_5_Fig3_HTML.jpg
Figure 5-3. An image set with the panda image inside

To show this image on the user interface we need to load it in an Image View. Views are normally composed on a storyboard, so that’s what we will do next. You already gained some experience with storyboards from Chapter 2 . Here we will build on it and go a bit further.

Working with the Storyboard

Xcode has a powerful visual editor, which lets you edit an application’s screens, arrange views, and connect UI elements with code in the corresponding view controller source file.

A storyboard consists of a sequence of scenes . Each scene represents a screen in the app and is composed of views such as buttons, labels, text views, and so on. Scenes also have corresponding view controller source files.

Transitions between scenes are also defined on the storyboard, using segue objects. Figure 5-4 shows an example of a storyboard with views, scenes and transitions between them.

A371202_1_En_5_Fig4_HTML.jpg
Figure 5-4. Storyboard elements

I know what you are thinking: can I create UI programmatically? The answer is yes, you can. Storyboards are usually preferred however. Not only do they let you rapidly design UI by dragging and dropping components onto a scene, but they also help visualize the appearance and the flow of your app.

Before we start creating the UI, let me make a quick note about the word “view” and its usage. In this chapter depending on the context a view can refer to an element of the user interface of the application, an implementation of type that inherits UIView class or an abstract entity, which displays information to the user.

Let us add an Image View to show the panda: Figure 5-5 illustrates the steps. Select Main.storyboard to open it in the storyboard editor. In Object library find an Image View and then drag and drop it onto the scene: initially it’s just a rectangle, which says “Image View.” To load the picture of the panda, with the Image View selected open Attributes inspector and set the Image drop-down to “bear.” The image is likely to be stretched and look out of proportion. In Attributes inspector set Mode to Aspect Fit to fix that.

A371202_1_En_5_Fig5_HTML.jpg
Figure 5-5. Add an Image View and display an image in it

Let us finish designing the UI by adding a Label and a Text Field below the panda Image View. In Object library search for a Label and drag and drop it onto the storyboard. With the Label selected go to Attributes inspector and change its text to “My name is.” If the Label’s text appears shortened, resize the label horizontally until you see the text without trailing ellipses (Figure 5-6). Now search for a Text Field view in the Object library and drag and drop it below the label.

A371202_1_En_5_Fig6_HTML.jpg
Figure 5-6. Add a label view and resize it

For now, do not worry if the UI is aligned or not: we will take care of this later on in the chapter.

Next are outlets and actions: you saw how to create them in Chapter 2 , now we will see why we need them.

Creating Outlets

All UI elements (views) we add onto the storyboard are instantiated as objects in memory when the app starts. The instances are created behind the scenes and we can’t access them unless we create references to them, called outlets.

An outlet is typically added as a property in a view controller class. It is marked with the @IBOutlet attribute, which makes it accessible to the storyboard: this serves as a connection between the storyboard and the code.

Create outlets for the Label and the Text Field in the ViewController class in ViewController.swift the way we learned to do it in Chapter 2 : open Main.storyboard and ViewController.swift side by side in Assistant editor and Ctrl+drag each UI element into the definition of the ViewController class. Name the Label outlet label and the Text Field outlet textField.

The ViewController class should now look like this (Listing 5-1):

Listing 5-1. Creating Outlets for the UI Elements
class ViewController: UIViewController
{
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var textField: UITextField!


    override func viewDidLoad()
    {
        super.viewDidLoad()
        // Do any additional setup after loading the view,
 // typically from a nib.
    }


    override func didReceiveMemoryWarning()
    {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Using the Target-Action Pattern

Target-Action is another design pattern, which the iOS SDK encourages you to use. It enables a system of objects to notify each other that an event has occurred and to target that event to an object that can act on it. You will typically see the pattern in situations where the app needs to react to an action done by the user, for example, tapping a button. The button view that receives the tap notifies a target object, which can perform an action in response.

In our context the target object is the ViewController instance. We will add a method to it, which will serve as the action to be performed when the user enters text in the text field: you can think of it as an event handler. This method has the following signature and is marked with the @IBAction attribute, which serves as a link between the storyboard and the code.

Listing 5-2. Signature of an Action Method
@IBAction func actionName(sender: AnyObject)

You gained some experience with adding actions to view controllers from Chapter 2 . Here is a quick reminder for how to do it: with Main.storyboard and ViewController.swift opened side by side, Ctrl+drag the Text Field from the storyboard into the definition of ViewController. Set the Connection in the pop-up dialog to Action, set Event to Editing Changed, name the action nameHasChanged, and click Connect to create the action method in ViewController (Figure 5-7).

A371202_1_En_5_Fig7_HTML.jpg
Figure 5-7. Creating an action

Leave action body empty for now. We will add logic to it in the next section, which shows you how to divide your code into layers of responsibilities with the Model-View-Controller pattern.

Model-View-Controller Design Pattern

This is the third pattern, which abounds in iOS programming and the iOS SDK is designed to let you take advantage of it. Whole applications are designed using this pattern. MVC is not new to the Flash and ActionScript world, so you may have already used it a number of times. The next section provides a quick intro, in case you would like a refresher.

MVC in Theory

The idea behind MVC is that the application is separated into three different functional layers: a model layer, which manages data; a view layer, which shows the data; and a controller layer, which controls how data is interacted with (Figure 5-8).

A371202_1_En_5_Fig8_HTML.jpg
Figure 5-8. Model-View-Controler pattern

The three layers are

  • Model—this is the part of the app that is responsible for managing data. It can include different data representations, business logic, and rules for how data is stored, retrieved, and edited.

  • View—this is what the user sees on the screen: the user interface. The View layer of your app should care about how it looks (how data is presented visually) but not where the data comes from or what happens when the user taps a button, for example.

  • ViewController—it binds the Model and the View together. The Controller gets the data from the Model and uses it to update the View. It also controls the logic of what happens when a button is tapped or an edit box text gets changed. When the user makes changes to the data presented by the View, the Controller commits these changes back to the Model.

The MVC pattern is such a common practice, that it won’t be very far from the truth if we said that it is present in any program with a graphical user interface. Note that MVC has many incarnations, each of which is subtly different from the rest. You will find versions where the View and the Model communicate directly, for example. Here we have presented Apple’s implementation of the pattern.

Let us structure our project in a way that will illustrate how MVC is meant to be used in iOS mobile apps.

Creating a Model

We will start by creating separate groups in the project tree for each part of the MVC triad . While this is not mandatory, it is considered to be a good practice to logically separate files for easy navigation around the project.

Create three new file groups by right-clicking the iOSProject folder in Project navigator and selecting New Group from the context menu (Figure 5-9). Name the groups Model, View, and Controller.

A371202_1_En_5_Fig9_HTML.jpg
Figure 5-9. Creating a new file group

As the names of the file groups imply, each group will hold the source files of the corresponding part of the MVC pattern. Drag the ViewController.swift file to move it to the Controller group. The project tree should look like Figure 5-10.

A371202_1_En_5_Fig10_HTML.jpg
Figure 5-10. Move ViewController.swift file to Cotroller group

Next we will create a Panda class that will hold data about our panda and will act as the Model in the application. Right-click the Model group and choose New File from the context menu. In the wizard that appears choose iOSSourceSwift file and name the file Panda.swift. Inside we will define the Panda class. The class will have one property of type String for the name of the panda: not a huge amount of data, but this will suffice to illustrate how to separate the data into the Model layer of the app. You can see the Panda class in Listing 5-3.

Listing 5-3. Panda Class Representing the Model from the MVC
import Foundation

class Panda {

    var name : String

    init( pandaName : String ){

        name = pandaName
    }
}

Setting Up the Controller

Next comes the Controller. The Controller’s task is to load the name of the panda from the Model, to commit the changes back to the Model when the user types a new name for the panda, and to update the View when the panda’s name changes (Listing 5-4).

Open ViewController.swift in the Code editor. First we will declare a constant property panda of type Panda and will set its name in the initializer to Cute. Not too original, but hey, look at that image: how could one resist? Go to the viewDidLoad() function and set the text property of the label outlet to "My name is (panda.name)" so when the app starts the label on the screen will say My name is Cute

The last thing to do in the Controller is to edit the model and to refresh the Label view when a change has been made. Remember the nameHasChanged(:) action we created earlier? It is called every time the user changes the text in the Text Field view. This is where we will update the data in the Model: that is, we set the name property of panda to what the user typed in the Text Field, which we access through the textField outlet. After the Model has been updated, we change label to show the modified data.

Listing 5-4. Filling Up the Controller
class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var textField: UITextField!


    //
    let panda : Panda = Panda(pandaName: "Cute")


    @IBAction func nameHasChanged(sender: AnyObject) {

        //Edit the model when text field view changes
        panda.name = textField.text!


        //Display the new name of the panda
        label.text = "My name is (panda.name)"
    }


    override func viewDidLoad() {
        super.viewDidLoad()


        //Display panda's name when the view is loaded
        label.text = "My name is (panda.name)"
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Creating a View

The final piece of the MVC puzzle is the View . While there are plenty of ready-to-use view components, there will be times when you need to implement a view with custom design and functionality. The good news is that you do not need to start writing the view from scratch, but you can use an existing view and extend it in a subclass. This is what we will do here. Imagine we want all of our panda images to have rounded corners and on a green background. The iOS SDK UIImageView class has properties that control the background and the radius of the corners, but if we want all panda images in the project to be rounded and green by default we can achieve this by creating a new view class.

Add a new file to the View group in the Project navigator. When the new file wizard appears select iOS ➤ Source ➤ Cocoa Touch Class and click Next. At the next step set the class name to RoundedImageView and make it a subclass of UIImageView. Click Next to create the new Swift file.

A371202_1_En_5_Fig11_HTML.jpg
Figure 5-11. Create a custom view class

When you open the new file, you will see that Xcode has already generated most of the code for the class. What is left for us to do is to access and modify the properties of the parent class that control the appearance of the view. We will do this in the awakeFromNib() method (Listing 5-5), which is called when the view is loaded from the Interface Builder archive.3 In this method we will modify the view a bit by setting its color to green and its corner radius to 10.0. We will also get the Image View to clip itself, so we can see the rounded corners.

Listing 5-5. RoundedImageView Class Implemetation
class RoundedImageView: UIImageView {

    override func awakeFromNib() {
        self.backgroundColor = UIColor.greenColor()
        self.layer.cornerRadius = 10.0;
        self.clipsToBounds = true;
    }
}

To use the newly created view class, open Main.storyboard and select the Image View. Open the Identity inspector and change Class to RoundedImageView as shown in Figure 5-12.

A371202_1_En_5_Fig12_HTML.jpg
Figure 5-12. Setting custom class to the image view

Now if you run the app in the simulator you will see how our cute panda sits on top of a green background with rounded corners (Figure 5-13).

A371202_1_En_5_Fig13_HTML.jpg
Figure 5-13. The app running in a simulator

So far in this chapter you learned how to structure your project using the MVC paradigm, what the Delegate pattern is, how to lay out the UI, and how to connect it to code using outlets and actions.

UI Layout Techniques

Now it is time to see how to align the views on the screen and how to set up the UI to look good on different screen sizes.

Auto Layout

When you design the UI of an application, you need to consider what its UI will look like on devices with different screen sizes and resolutions. Making it adaptive to different screen orientations is also a good thing: Auto Layout is a tool that does that by automatically recalculating the size and position of every element on the screen, taking into account any predefined constraints you have set.

We will do a bit of planning for the UI of our app. Let’s say we want the panda image to be horizontally centered on the screen and to have its top edge at 20 pixels from the top of the screen. We also want the vertical gap between all views to be 20 pixels. The Label view will take all the available width of the screen and the width of the Text Field view will be half of the width of the Label. See the UI sketch in Figure 5-14.

A371202_1_En_5_Fig14_HTML.jpg
Figure 5-14. Sketching out the sizes and positions of the elements in the app’s UI

We also want these constraints to hold on every iOS device and for every screen orientation. If your lips are forming the question “Why?!,” let’s assume that this is what the client who has commissioned this app wants. This probably raises another “Why?!,” but let’s not go there. . . .

To see what the design looks like on different devices while we are still working on it, toggle the storyboard Preview window (Figure 5-15): select Main.storyboard and open the Assistant editor. Find the Assistant menu button and select Preview ➤ Main.storyboard.

A371202_1_En_5_Fig15_HTML.jpg
Figure 5-15. Show the Preview window

You can add multiple previews for different devices by clicking the + button at the bottom. Click it and select iPad and iPhone5.5 from the pop-up menu (Figure 5-16). You can see how the panda is not centered on the iPhone preview and all of the views (Image View, Label, and Text Field) appear clipped.

A371202_1_En_5_Fig16_HTML.jpg
Figure 5-16. Add devices for preview

Let’s add some constraints that will keep the views aligned. You can think of a constraint as a rule that you want a view to follow. For example, you can say that you want the top edge of the view to be positioned at a certain distance from the top edge of the screen or that two views should always maintain the same height.

All of the constraints put together form a system of linear equations. When solved, they result in actual numbers for the views’ widths, heights and positions. Solving the system is Auto Layout’s job.

There are two types of constraints . The first type is applied to a single view, for example, to give it a fixed width or height. The second type is defined as requirements for one view, relative to another view.

You had a go at using the Auto Layout tools back in Chapter 2 and we will put them to use again. Start by selecting the Image View and click the Pin button. Set Spacing to nearest neighbor to 20 pixels to the top of the scene. Set Height to 98 pixels, tick Aspect ratio, and click Add 3 Constraints. You will see the constraints appear in the document outline on the left (Figure 5-17). A note: we only added the Aspect ratio constraint temporarily: it will prevent Auto Layout from stretching the image while we are adding other constraints (i.e. while the system of equations is still underdefined); we will get rid of it later.

A371202_1_En_5_Fig17_HTML.jpg
Figure 5-17. Pin the image view

Next, select the Label and open the Pin dialog again. Pin the Label at 20 pixels vertically away from the Image View by setting the top Space to nearest neighbor to 20 pixels. Set the left and the right spaces to 10 pixels each: this will be the distance that the Label will maintain from the edges of its parent view. Click Add 3 constraints to apply them to the scene (Figure 5-18).

A371202_1_En_5_Fig18_HTML.jpg
Figure 5-18. Pin the label view

Pin the Text Field 20 pixels away from its nearest neighbor at the top and at 10 pixels from the left and from the right edge of its parent view.

To set the width of the Text Field to half that of the Label, select both views, open the Pin dialog and check the Equal Widths checkbox, then click Add 1 Constraint (Figure 5-19).

A371202_1_En_5_Fig19_HTML.jpg
Figure 5-19. Constrain the width of the Text Field view

Setting the two UI elements to have equal widths when we are aiming to have one of them half the width of the other may seem a bit confusing. We will fix this in a minute.

With the Text Field selected open Size inspector (Figure 5-20), find the Equal Widths constraint, and double-click to edit it.

A371202_1_En_5_Fig20_HTML.jpg
Figure 5-20. Size inspector

The first three fields in the Equal Widths Constraint form determine the two UI elements that the constraint will take into account or affect (Figure 5-21): First item should be set to Mlabel.Width and Second Item should be set to MText Field.Width.

A371202_1_En_5_Fig21_HTML.jpg
Figure 5-21. Adjusting the width multiplier

If you have a look further down the form, you will see a setting called Multiplier: this is what will help us set the correct proportion for the widths. The Multiplier setting is used to calculate a property proportional to another property. In this case it will be used for setting the width of the Text Field proportional to the width of the Label. The Multiplier, as its name implies, multiplies the selected property of the Second Item and applies the result to the selected property of the First item. We can set the Multiplier value to any floating point number: 1.0 means that the two properties should be equal. To make Text Field half the width of the Label, we need to set Multiplier to 0.5.

The last thing left to do is to center the panda horizontally on the screen. Select the Image View and its parent view (the screen in this example) and click the Align button (Figure 5-22). Tick Leading Edges and Trailing Edges and click Add 2 Constraints.

A371202_1_En_5_Fig22_HTML.jpg
Figure 5-22. Align the Image View and the Superview leading and trailing edges

In the Document outline panel select the leading edge constraint you just created (Figure 5-23). Then, with the constraint selected, in Size inspector set Second item to Superview.Center.X and Multiplier to 0.5. This sets the left edge of the Image View in the middle of the first 50% of its containing view.

A371202_1_En_5_Fig23_HTML.jpg
Figure 5-23. Align the Image View’s leading edge to 50% to the left of the Superview center

To actually center the Image View, we have to set its right edge to be in the middle of the second 50% of its containing view. To apply this logic select the Trailing Edge constraint in Document outline (Figure 5-24), then in Size inspector set Second item to Superview.Center.X and Multiplier to 1.5.

A371202_1_En_5_Fig24_HTML.jpg
Figure 5-24. Align Image View trailing edge to 50% to the right of the Superview center

You may have noticed that even after editing the Multiplier setting the panda is still not centered properly. This is because the system now has one constraint too many. Select the Aspect Ratio constraint that we temporarily set earlier for the Image View and delete it. Now you should see the panda image centered on all devices in the Preview window (Figure 5-25).

A371202_1_En_5_Fig25_HTML.jpg
Figure 5-25. The app’s user interface on different screen sizes

And thus we made the UI of the app responsive. Next we will see how to enhance an Auto Layout, so we can fully master the real estate of different screen sizes.

Size Classes

Having an adaptive UI is not always the whole story. Sometimes you want your application to make different use of different screen sizes and change its look (not just resize itself) depending on what device and what orientation it is used in. For example, a video chat app that shows video in its top half and a text area for typing in its bottom half on an iPad and on an iPhone in portrait orientation may be better presented with the video view taking the whole screen when the iPhone is rotated to landscape. Before iOS 8 providing these two different looks meant creating and maintaining two storyboards, which often resulted in duplicated work.

Size Classes were introduced to help with that. Here the word “class” is used to mean “category” rather than the object-oriented programming concept. They work together with Auto Layout: instead of having the same constraints apply to your UI all the time, you can categorize them. In other words, you can choose a constraint to only be applied in a certain case by setting it to belong to a given Size Class.

There are two main types of Size Classes: horizontal and vertical. They can be set to one of three options: Regular, Compact or Any. Each combination corresponds to a different device and screen orientation, summarized in Table 5-1.

Table 5-1. Size Classes–Devices Correspondence
 

Horizontal Size Class

Vertical Size Class

 

Regular

Compact

Regular

Device: iPad

Orientation: portrait, landscape

Device: iPhone

Orientation: portrait

Compact

 

Device: iPhone

Orientation: landscape

We will set constraints for the cute panda app and classify them with Size Classes to get a different look on the iPad. Imagine a client called to ask that only on the iPad all views be moved toward the bottom of the screen by 500 pixels.

Before we set the new constraints, we need to specify that we are now designing for the iPad screen size. With the storyboard open click the Size Class button and select Regular row and Regular column (Figure 5-26).

A371202_1_En_5_Fig26_HTML.jpg
Figure 5-26. Set Size Classes to match iPad (Regular | Regular)

Select the panda image view and pin its top at 500 pixels from the top edge of its parent view (Figure 5-27). You might notice that the bottom bar of the Interface builder has changed to blue: this is Xcode’s way of reminding us that we are working in a Size Class mode different than Any | Any.

A371202_1_En_5_Fig27_HTML.jpg
Figure 5-27. Pin the Image View to Top with 500 pixels for the iPad

Now if you look at the Preview window, you will see how all the views appear lower down only on the iPad preview (Figure 5-28).

A371202_1_En_5_Fig28_HTML.jpg
Figure 5-28. The iPad preview now looks different from the rest

This is the power of Size Classes.

Resolving Layout Issues

While designing the UI of the app you will inevitably stumble upon some red and orange lines around some of the view elements (Figure 5-29). This is how Interface Builder informs you about possible issues in the layout that you must consider resolving.

A371202_1_En_5_Fig29_HTML.jpg
Figure 5-29. Constraints issues indicator lines

The orange lines are used as a warning that there might be a missing constraint or that the Interface Builder has a suggestion for changing a constraint value. The red lines appear when there are conflicting constraints.

There are two ways to handle layout issues. You can try to edit the constraints manually until the Interface Builder is satisfied, or you can use the Resolve Auto Layout Issues tools, a button placed at the bottom of the storyboard editor panel (Figure 5-30).

A371202_1_En_5_Fig30_HTML.jpg
Figure 5-30. Resolve Auto Layout Issues

There are several options from which we can choose:

  • Update Frames. This will update the frame of the selected view to match the constraints that were added.

  • Update Constraints. This will do the opposite and change the values of the constraints to match what you see in the scene.

  • Add Missing Constraints. If the applied constraints are not enough to resolve the layout, this operation will try to add the necessary constraints in order to satify the layout engine.

  • Reset to Suggested Constraints. This will replace all constraints applied to the selected view with new ones suggested by the layout engine.

  • Clear Constraints. This does what its name implies and removes all constraints from the selected view.

Try to avoid issues by adding just enough constraints to the views. If you add too little, you will create ambiguities; if you overconstrain the views, the chance to have conflicting constraints increases.

Summary

In this chapter you saw how to apply three different design patterns, very much encouraged and employed by the iOS SDK: Delegation, Target-Action, and Model-View-Controller.

You used the MVC pattern to structure an application and implemented a custom view in it. You then made its UI responsive and adaptive with Auto Layout and Size Classes.

You should be proud of yourself. Now buckle up and prepare to enter the deep waters of the advanced UI presented in the next chapter.

Footnotes

1 “The gang of four” famously opened their book on design patterns with “Don’t worry if you don’t understand this book completely on the first reading. We didn’t understand it all on the first writing!” Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley 1995).

2 Here is the link to the image I’m using, in case you want to download the same one: https://pixabay.com/en/panda-bear-cute-happy-young-151587 .

3 During the build phase of the project all views and storyboards you have created are archived in .nib files. When a .nib file is loaded in memory, all of its contents get unachieved or awakened. If instead of a .nib you stumble upon an .xib, do not panic: they both have the exact same information inside; just store it in a different way. So you can think about .nib and .xib as synonyms.

..................Content has been hidden....................

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