Connecting to Code
You know how to make an interface, but how do you make it do something? Throughout this hour, I’ve been alluding to the idea that connecting an interface to the code you write is just a matter of “connecting the dots.” In this last part of the hour, we do just that: take an interface and connect it to the code that makes it into a functional application.
Opening the Project
To get started, we use the project Disconnected contained within this hour’s Projects folder. Open the folder and double-click the Disconnected.xcodeproj file. This opens the project in Xcode, as shown in Figure 5.17.
FIGURE 5.17 To begin, open the project in Xcode.
After the project is loaded, expand the project code group (Disconnected) and click the Main.storyboard file. This storyboard file contains the scene and view that this application displays as its interface. Xcode refreshes and displays the scene in IB, as shown in Figure 5.18.
FIGURE 5.18 IB displays the scene and corresponding view for the application.
The interface contains four interactive elements: a button bar (called a segmented control), a push button, an output label, and a web view (an integrated web browser component). Together, these controls interface with application code to enable a user to pick a flower color, touch the Get Flower button, and then display the chosen color in a text label along with a matching flower photo fetched from the website http://www.floraphotographs.com. Figure 5.19 shows the final result.
FIGURE 5.19 The finished application enables a user to choose a color and have a flower image returned that matches that color.
Unfortunately, right now the application does nothing. The interface isn’t connected to any application code, so it is hardly more than a pretty picture. To make it work, we create connections to outlets and actions that have been defined in the application’s code.
Outlets and Actions
An outlet is nothing more than a variable property by which an object can be referenced. For example, if you had created a field in IB intending that it would be used to collect a user’s name, you might want to create an outlet for it in your code called userName. Using this outlet and a corresponding variable property, you could then access or change the contents of the field.
An action, however, is a method within your code that is called when an event takes place. Certain objects, such as buttons and switches, can trigger actions when a user interacts with them through an event, such as touching the screen. If you define actions in your code, IB can make them available to the onscreen objects.
Joining an element in IB to an outlet or action creates what is generically termed a connection. For the Disconnected app to function, we need to create connections to these outlets and actions:
- colorChoice: An outlet created for the button bar to access the color the user has selected
- getFlower: An action that retrieves a flower from the Web, displays it, and updates the label with the chosen color
- chosenColor: An outlet for the label that will be updated by getFlower to show the name of the chosen color
- flowerView: An outlet for the web view that will be updated by getFlower to show the image
Let’s make the connections now.
Creating Connections to Outlets
To create a connection from an interface item to an outlet, Control-drag from a scene’s View Controller icon (in the document outline area or the icon bar below the view) to either the visual representation of the object in the view or its icon in the document outline area.
Try this with the button bar (segmented control). Pressing Control, click and drag from the view controller in the document outline area to the onscreen image of the bar. A line appears as you drag, enabling you to easily point to the object that you want to use for the connect, as shown in Figure 5.20.
FIGURE 5.20 Control-drag from the view controller to the button bar.
When you release the mouse button, the available connections are shown in a pop-up menu (see Figure 5.21). In this case, you want to pick colorChoice.
FIGURE 5.21 Choose from the outlets available for the targeted object.
Repeat this process for the label with the text "Your Color", connecting it to the chosenColor outlet, and with the web view, connecting to flowerView.
Connecting to Actions
Connecting to actions is a bit different. An object’s events trigger actions (methods) in your code. So, the connection direction reverses; you connect from the object invoking an event to the view controller of its scene. Although it is possible to Control-drag and create a connection in the same manner you did with outlets, this isn’t recommended because you don’t get to specify which event triggers it. Do users have to touch the button? Release their fingers from a button?
Actions can be triggered by many different events, so you need to make sure that you’re picking exactly the right one, instead of leaving it up to IB. To do this, select the object that will be connecting to the action and open the Connections Inspector by clicking the arrow icon at the top of the Xcode utility area. You can also show the inspector by choosing View, Utilities, Show Connections Inspector (or by pressing Option-Command-6).
The Connections Inspector, in Figure 5.22, shows a list of the events that the object, in this case a button, supports. Beside each event is an open circle. To connect an event to an action in your code, click and drag from one of these circles to the scene’s View Controller icon in the document outline area.
FIGURE 5.22 Use the Connections Inspector to view existing connections and to make new ones.
For example, to connect the Get Flower button to the getFlower method, select the button, and then open the Connections Inspector (Option-Command-6). Drag from the circle beside the Touch Up Inside event to the scene’s view controller and release, as demonstrated in Figure 5.22. When prompted, choose the getFlower action, shown in Figure 5.23.
FIGURE 5.23 Choose the action you want the interface element to invoke.
After a connection has been made, the inspector updates to show the event and the action that it calls, demonstrated in Figure 5.24. If you click other already connected objects, you’ll notice that the Connections Inspector shows their connections to outlets and to actions.
FIGURE 5.24 The Connections Inspector updates to show the actions and outlets that an object references.
Well done! You’ve just linked an interface to the code that supports it. Click Run on the Xcode toolbar to build and run your application in the iOS Simulator or on your personal iDevice.
Editing Connections with the Quick Inspector
One of the errors that I commonly make when connecting my interfaces is creating a connection that I didn’t intend. A bit of overzealous dragging, and suddenly your interface is wired up incorrectly and won’t work. To review the connections that are in place, you select an object and use the Connections Inspector discussed previously, or you can open the Quick Inspector by right-clicking any object in the IB editor or document outline area. This opens a floating window that contains all the outlets and actions either referenced or received by the object, as shown in Figure 5.25.
FIGURE 5.25 Right-click to quickly inspect any object connections.
Besides viewing the connections that are in place, you can remove a connection by clicking the X next to a connected object (see Figure 5.24 and 5.25). You can even create new connections using the same “click-and-drag from the circle to an object” approach that you performed with the Connections Inspector. Click the X in the upper-left corner of the window to close the Quick Inspector.
Writing Code with IB
You just created connections from UI objects to the corresponding outlets and actions that have already been defined in code. In the next hour’s lesson, you write a full application, including defining outlets and actions and connecting them to a storyboard scene. What’s interesting about this process, besides it bringing all the earlier lessons together, is that IB editor writes and inserts the necessary Swift code to define outlets and actions.
Although it is impossible for Xcode to write your application for you, it does create the instance variables and properties for your app’s interface objects, as well as “stubs” of the methods your interface will trigger. All you need to do is drag and drop the IB objects into your source code files. Using this feature is completely optional, but it does help save time and avoid syntax errors.
As we finish up our introduction to IB, I’d be remiss if I didn’t introduce one more feature: the Identity Inspector. You’ve already accessed this tool to view the accessibility attributes for interface objects, but there is another reason why we need to use the inspector in the future: setting class identities and labels.
As you drag objects into the interface, you’re creating instances of classes that already exist (buttons, labels, and so on). Throughout this book, however, we build custom subclasses that we also need to be able to reference with IB’s objects. In these cases, we need to help IB by identifying the subclass it should use.
For example, suppose we created a subclass of the standard button class (UIButton) that we named ourFancyButtonClass. We might drag a button into a scene to represent our fancy button, but when the storyboard file loads, it would just create the same old UIButton.
To fix the problem, we select the button we’ve added to the view, open the Identity Inspector by clicking the window icon at the top of the Xcode utility area or by choosing View, Utilities, Show Identity Inspector (Option-Command-3), and then use the drop-down menu/field to enter the class that we really want instantiated at runtime (see Figure 5.26).
FIGURE 5.26 If you’re using a custom class, you need to manually set the identity of your objects in the Identity Inspector.
This is something we cover on an as-needed basis; so if it seems confusing, don’t worry. We come back to it later in the book.