A touching example: the event reporter (iOS 4)

The sample application for events is an event reporter, which offers a variety of responses depending on how and when the device screen is touched. The sample program has two goals.

First, we want to show you a cool and simple application that you can write using events—one that should get you thinking about everything you can do.

Second, we want to show some of the low-level details of how events work in a visual form. If you take the time to code and compile this program, you’ll gain a better understanding of how the various phases work as well as how tapping works.

You’ll kick off this development process by creating a project named eventreporter that uses the View-Based Application template. That means you’ll start with a view controller already in place. We’ll also use this example to show how an MVC program can be structured.

Setting things up in Interface Builder

For this program, you’ll create three new objects: two button-shaped objects that float around the screen to mark the beginning and end of touches, plus a status bar to go at the bottom of the screen and describe a few other events when they occur.

Because you want all your new objects to lie beneath the view controller in the view hierarchy, you call up the view controller’s own .xib file, eventreporterView-Controller.xib. As usual, you’ll add your new objects to the Main Display window that represents the view controller’s view.


All this work is graphical, so we can’t show the code of this programming process.

But we’ve included a quick summary of the actions you should take (the results are shown in figure 6.3):

■ Set the background color of the UIView to an attractive aluminum color. You do this in the Attributes Inspector, as you do most of your work in this project.

■ Create a UILabel, stretch it across the bottom of the screen, and set the color to be steel. Also, clear its text so it doesn’t display anything at startup.

■ Create two UITextFields. This class of objects is generally used to accept input, but we opted to use the objects for pure display purposes because we like their look. (Don’t worry; we’ll show how to use the full functionality of a UIText-Field toward the end of this topic.)

■ Place each UITextField at the center of the screen using the handy positioning icons as guides. Set this location’s coordinates to 159, 230; and set its origin to middle.

Two UITextFields (one of them hidden) and one UILabel, set against an aluminum-colored background on the iPhone, complete the object creation you need for your eventreporter project.

Figure 6.3 Two UITextFields (one of them hidden) and one UILabel, set against an aluminum-colored background on the iPhone, complete the object creation you need for your eventreporter project.

■ For each UITextField, input text that lists its starting position; this will later be updated by the program as the text field moves. Deselect the user interaction-enabled option for each UITextField so that users can’t manipulate them.

The process takes longer to explain than it takes to accomplish. You’ll have a working interface in a couple of minutes.

Because you’ll modify all three of these objects during the course of your program’s runtime, you need to link them to variables. You should link everything to your controller, because it takes care of updates, as is appropriate under the MVC model.

The tricky thing here is that the view controller doesn’t seem to appear in your eventreporterViewController.xib file—at least not by that name. Fortunately, there’s a proxy for it. Because the view controller is what loads up the .xib, it appears as the file’s owner in the nib document window. You can therefore connect objects to the view controller by linking them to the file’s owner proxy. This is a common situation, because view controllers frequently load additional .xib files for you.

The following is your view controller’s header file, eventreportViewController.h, following the addition of these IBOutlets. The code also contains a declaration of a method that you’ll use later in this project:

tmp12144_thumb

To finish this process, connect your inter face objects to the IBOutlets, using the procedures described in topic 4.

Preparing a view for touches

Touch events can be captured only by UIView objects. Unfortunately, as of this writing, there’s no way to automatically delegate those touches to a view controller. Therefore, in order to manage touch events using the MVC model, you typically need to subclass a UIView, capture the events there, and then send messages to the view controller.

In this project, you create a new object class, reportView, which is a subclass of UIView. You then link, visually, that new class into the view controller’s existing view. Open eventreporterViewController.xib, go to the Identity tab for the view object you’ve been using, and change its name from UIView to reportView, as you did in topic 5 when you created a table view controller subview.

Any new methods you write into reportView, including methods that capture touch events, will be now reflected in your view. To clarify this setup, figure 6.4 shows the view hierarchy that you’ve built for your even-treporter project.

You'll connect six objects that you'll use to report events.

Figure 6.4 You’ll connect six objects that you’ll use to report events.

With a brand-new UIView subclass in hand, you can now write methods into it to capture touch events and forward them to its controller. This code, which appears in reportView.m, is as follows:

tmp12146_thumb

This code is pretty simple. You’re filling in standard methods so that your program will have the responses you want when those messages are sent. The overall structure of these methods reminds us of several important facts about events.

First, as promised, there are a variety of responder methods. Each of them reports only the events for its specific phase. So, for example, the touchesBegan:withEvent: method only has UITouchPhaseBegan touches in it. In forwarding these touches, you could keep the different phases distinct, but instead you throw everything together and sort it out on the other side.

Second, we’ll comment one final time that these methods send you two pieces of information: a set of touches and an event. They’re partially redundant, and which one you work with will probably depend on the work you’re doing. If you’re not doing complex multitouch events, then the NSSet of touches will probably be sufficient.

An aside on the text fields and label

If you were to code in this example, you’d discover that the program correctly responds to touch events even when the touches occur atop one of the text fields or the label at the bottom of the page. How does the program manage that when you built event response into only the reportView?

The answer is this: it uses the responder chain. The text fields and the label don’t respond to the event methods themselves. As a result, the events are passed up the responder chain to the reportView, which does leap on those events, using the code you’ve just seen.

Third, note that you’re sending the touches to the view controller by way of the next-Responder method. As you’ll recall, the responder chain is the opposite of the view hierarchy at its lower levels, which means in this case the nextResponder of report-View is the UIViewController. We would have preferred to have the UIViewController naturally respond to the touches’ messages, but we made use of the responder chain in the next-best way. As of this writing, the compiler warns that nextResponder may not know about the manageTouches method, but it will; you can ignore this warning.

You’ll see some other ways to use the nextResponder method toward the end of our discussion of events.

Controlling your events

Intercepting touches and forwarding them up to the view controller may be the toughest part of this code. After the events get to the view controller, they run through a simple method called manageTouches:, as in the following listing, which shows the view controller implementation file.

Listing 6.1 manageTouches, which accepts inputs and changes views

Listing 6.1 manageTouches, which accepts inputs and changes views

Touches are sent as an NSSet, which can be broken apart in a number of ways, as described in the NSSet class reference. Here, you use a simple for … in construction that lets you look at each touch in turn.

When you get a touch, the first thing you do is determine what phase it arrived in. Originally, you could have determined this information based on which method a touch arrived through, but because you combined everything you have to fall back on the phase property. Fortunately, it’s easy to use. You match it up to one of three constants O, and that determines which individual actions your program undertakes.

Having different responses based on the phase in which a touch arrives is com-mon—which is why the event methods are split up in the first place. The example demonstrates this with some distinct responses: you move your start field when touches begin, you move your end field when touches end, and you update the bottom label in both the moved and ended phases.

In the UITouchPhaseBegan response, you delve further into your touches’ data by using the locationInView: method to figure out the precise coordinates where a touch occurred. You’re then able to use that data to reposition your text field and to report the coordinates in the text field. You later do the same thing in the UITouch-PhaseEnded response.

Finally, you look at the tapCount in the UITouchPhaseEnded response. This is generally the best place to look at taps because the device now knows that the user’s finger has come off the screen. As you can see, it’s easy to both run a command based on the number of taps and to report that information.

Figure 6.5 shows the event responder in action. Imagine a finger that touches down on the space where the Begin text field is and that is currently moving across the screen.

And with that, your event reporter is complete. In addition to illustrating how a program can respond to touches, we’ve highlighted how the MVC model can be used in a real application.

The project contains four views: a reportView, a UILabel, and two UITextFields. It’s tempting to process events in the reportView, especially because you had to create a subclass anyway, but instead you pushed the events up to the view controller and in doing so revealed why you want to do MVC modeling.

Because it takes on the controller role, you give the view controller access to all of its individual objects, and therefore you don’t have to try to remember what object knows about what other object.

Your event responder uses a few graphical elements to report events as they occur.

Figure 6.5 Your event responder uses a few graphical elements to report events as they occur.

Tying things into the view controller, rather than scattering them randomly across your code, makes the project that much more readable and reusable, which is what most architectural and design patterns are about.

Next post:

Previous post: