It starts out at the first responder of the key window, which is typically the view where the event occurred—in other words, where the user touched the screen.. Any object in the chain
Trang 1Monitoring events and actions
In the previous chapter you learned how to create the basic view controllers that fulfill the controller role of an MVC architectural model You’re now ready to start accepting user input, since you can now send users off to the correct object Users can interact with your program in two ways: by using the low-level event model or
by using event-driven actions In this chapter, you’ll learn the difference between the two types of interactions Then we’ll look at notifications, a third way that your program can learn about user actions
Of these three models, it’s the events that provide the lowest-level detail (and which ultimately underlie everything else), and so we’ll begin with events
14.1 An introduction to events
We briefly touched on the basics of event management in chapter 10, but as we said
at the time, we wanted to put off a complete discussion until we could cover them
in depth; we’re now ready to tackle that job
This chapter covers
■ The SDK’s event modeling
■ How events and actions differ
■ Creating simple event- and action-driven apps
Trang 2Part 1 of this book, dealing with web design, outlined how events tend to work on the iPhone The fundamental unit of user input is the touch: a user puts his finger on the screen This could be built into a multi-touch or a gesture, but the touch remains the building block on which everything else is constructed It’s thus the basic unit that we’re going to be examining in this chapter.
14.1.1 The responder chain
When a touch occurs in an SDK program, you have to worry
about something you didn’t have to think about on the
web: who responds to the event That’s because SDK
pro-grams are built of tens—perhaps hundreds—of different
objects Almost all of these objects are subclasses of the
UIResponder class, which means they contain all the
func-tionality required to respond to an event So who gets
to respond?
The answer is embedded in the concept of the
responder chain This is a hierarchy of different objects
that are each given the opportunity, in turn, to answer an
event message
Figure 14.1 shows an example of how an event moves up
the responder chain It starts out at the first responder of the
key window, which is typically the view where the event
occurred—in other words, where the user touched the
screen As we’ve already noted, this first responder is
prob-ably a subclass of UIResponder—which is the class reference
you’ll want to look to for a lot of responder functionality
Any object in the chain may accept an event and resolve it, but whenever that doesn’t occur the event moves further up the list of responders From a view, an event
will go to its superview, then its superview, until it eventually reaches the UIWindow
object, which is the superview of everything in your application It’s useful to note that from the UIWindow downward, the responder chain is the view hierarchy turned on its head, so when you’re building your hierarchies, they’ll be doing double duty
Although figure 14.1 shows a direct connection from the first responder to the window, there could be any number of objects in this gap in a real-world program
Often the normal flow of the responder chain will be interrupted by delegation A
specific object (usually a view) delegates another object (usually a view controller) to act for it We already saw this put to use in our table view in chapter 13, but we now understand that a delegation occurs as part of the normal movement up the responder chain
If an event gets all the way up through the responder chain to the window and it can’t deal with an event, then it moves up to the UIApplication itself, which most fre-
quently punts the event to its own delegate: the application delegate, an object that we’ve
been using in every program to date
App Delegate
The Application
The Window
First Responder
Figure 14.1 Events on the iPhone are initially sent to the first responder, but then travel up the responder chain until someone accepts them.
Trang 3Ultimately you, the programmer, will be the person who decides what in the sponder chain will respond to events in your program You should keep two factors in mind when you make this decision: how classes of events can be abstracted together at higher levels in your chain, and how you can build your event management using the concepts of MVC.
At the end of this section we’ll address how you can subvert this responder chain
by further regulating events, but for now let’s build on its standard setup
14.1.2 Touches and events
Now that you know a bit about how events find their way to the appropriate object, we can dig into how they’re encoded by the SDK First we want to offer a caveat: usually you won’t need to worry about this level of detail because the standard UIKit objects will generally convert low-level events into higher-level actions for you, as we discuss
in the second half of this chapter With that said, let’s look at the nuts and bolts of event encoding
The SDK abstracts events by combining a number of touches (which are sented by UITouch objects) into an event (which is represented by a UIEvent object)
repre-An event typically begins when the first finger touches the screen and ends when the last finger leaves the screen In addition, it should generally only include those touches that happened in the same view
In this chapter we’ll work mainly with UITouches (which make it easy to parse gle-touch events) and not with UIEvents (which are more important for parsing multi-touch events) Let’s lead off with a more in-depth look at each
sin-First responders and keyboards
Before we leave this topic of responders behind, we’d like to mention that the first responder is a very important concept Because this first responder is the object that can accept input, it’ll sometimes take a special action to show its readiness for input This is particularly true for text objects like UITextField and UITextView, which (if editable) will pop up a keyboard when they become the first responder This has two immediate consequences
If you want to pop up a keyboard for the text object, you can do so by turning it into the first responder:
Trang 4to-UITOUCH REFERENCE
A UITouch object is created when a finger is placed on the screen, moves on the screen, or is removed from the screen A handful of properties and instance methods can give you additional information on the touch, as detailed in table 14.1
Together the methods and properties shown in table 14.1 offer considerable tion on a touch, including when and how it occurred
Only the phase property requires additional explanation It returns a constant that can be set to one of five values: UITouchPhaseBegan, UITouchPhaseMoved, UITouch-PhaseStationary, UITouchedPhaseEnded, or UITouchPhaseCancelled You’ll often want to have different event responses based on exactly which phase a touch occurred
in, as you’ll see in our event example
UIEVENT REFERENCE
To make it easy to see how individual touches occur as part of more complex gestures, the iPhone SDK organizes UITouches into UIEvents Figure 14.2 shows how these two sorts of objects interrelate
Just as with the UITouch object, the UIEvent object contains a number of properties and methods that you can use to figure out more information about your event, as described in table 14.2
Table 14.1 Additional properties and methods can tell you precisely what happened during a touch event Method or property Type Summary
whether touch began, moved, ended, or was canceled
view Property The view where the touch began
locationInView: Method Gives the current location of the touch in the specified
UITouchPhaseEnded locationInView:
(28,32)
UITouch phase:
UITouchPhaseMoved locationInView:
Trang 5The main use of a UIEvent method is to give you a list of related touches that you can break down by several means If you want to get a list of every touch in an event, or if you want to specify just gestures on a certain part of the screen, then you can do that with UIEvent methods This ends our discussion of event containers in this chapter Note that all of these methods compact their touches into an NSSet, which is an object defined in the Foundation framework You can find a good reference for the NSSet at Apple’s developer resources site.
THE RESPONDER METHODS
So, how do you actually access these touches and/or events? You do so through a series of four different UIResponder methods, which are summarized in table 14.3 Each of these methods has two arguments: an NSSet of touches that occurred during the phase in question and a UIEvent that provides a link to the entire event’s worth of touches You can choose to access either one, as you prefer; as we’ve said, we’re going
to be playing with the bare touches With that said, we’re now ready to dive into an actual example that demonstrates how to capture touches in a real-life program
14.2 A touching example: the event reporter
Our sample application for events is something we call the event reporter, which will offer a variety of responses depending on how and when the iPhone screen is touched We have two goals with our sample program
Table 14.2 The encapsulating event object has a number of methods and properties
that let you access its data.
Method or property Type Summary
touchesForView: Method All event touches associated with a view
touchesForWindow: Method All event touches associated with a window
Table 14.3 The UIResponder methods are the heart of capturing events.
touch the screen
move across the screen
leave the screen
the phone is put up to your head, or other events that might cause an external cancellation
Trang 6First, 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 Therefore, if you actually take the trouble to code and compile this program, you’ll gain a better understanding of how the various phases work as well as how tap-ping works
You’ll kick off this development process by creating a project named eventreporterthat uses the View-Based Application template That means you’ll start with a view con-troller already in place We’ll also use this example to show how an MVC program can
be structured
14.2.1 Setting things up in Interface Builder
By now you should be comfortable enough
with Interface Builder that you can set up all of
your basic objects using it For this program
we’ve decided that we want to create three new
objects: two button-shaped objects that will
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 of our new objects to
lie beneath the view controller in the view
hier-archy, you call up the view controller’s own
.xib file, eventreporterViewController.xib As
usual, you’ll add your new objects to the Main
Display window that represents the view
con-troller’s view
All of your work in Interface Builder is, of
course, graphical, so we can’t show the code
of this programming process However, we
have included a quick summary of the actions
you should take The results are shown in
fig-ure 14.3
■ Set the background color of the UIView to an attractive aluminum color You do this on the Attributes tab of the Inspector window, as you would with 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 out its text so that 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 our pure display purposes because we liked their look (Don’t worry; we’ll show how to use the full functionality of a UIText-Field toward the end of this chapter.)
Figure 14.3 Two UITextFields (one
of them hidden) and one UILabel, all set against an aluminum-colored background, complete the object creation we’ll need for our eventreporter project.
Trang 7■ Center each UITextField at the center of the screen using Interface Builder’s handy positioning icons This location’s coordinates will be 159, 230.
■ 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 interac-tion–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 just a couple of minutes
CREATING IBOUTLETS
Because you’ll modify all three of these objects during the course of your program’s runtime, you need to link them to variables inside Xcode You’ll want to link every-thing to your controller, since it’ll be taking 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 our eventreporterViewController.xib file—at least not by that name Fortunately, there’s a proxy for it Since 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, since view controllers frequently load additional xib files for you
Listing 14.1 shows your view controller’s header file, eventreportViewController.h, following the addition of these IBOutlets The listing also contains a declaration of a method that you’ll use later in this project
@interface eventreporterViewController : UIViewController {
IBOutlet UITextField *startField;
IBOutlet UITextField *endField;
IBOutlet UILabel *bottomLabel;
14.2.2 Preparing a view for touches
Touch events can only be captured 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’ll typically need to class a UIView, capture the events there, and then send messages to the view control-ler
In your project you’ll create a new object class, reportView, which is a subclass of UIView You then link that new class into the view controller’s existing view through Interface Builder You open up eventreporterViewController.xib, go to the Identity tabListing 14.1 An IB-linked header
Trang 8for the view object that you’ve been using, and change its
name from UIView to reportView, just as you did in
chap-ter 13 when you created a table view controller subview
Any new methods that you write into reportView,
including methods that capture touch events, will be now
reflected in your view To clarify this setup, figure 14.4
shows the view hierarchy that you’ve built for your
even-treporter project
With a brand-new UIView subclass in hand, you can
now write methods into it to capture touch events and
forward them on to its controller This code, which
appears in reportView.m, is shown in listing 14.2
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
only the events for their specific phase So, for example, the
touchesBegan:with-Event: method would only have UITouchPhaseBegan touches in it In forwarding on these touches we could have kept the different phases distinct, but we’ve instead decided to throw everything together and sort it out on our own on the other side Second, we’ll comment one final time that these methods send us two pieces of information: a set of touches and an event They are partially redundant, and which one you work with will probably depend on the work you’re doing If you’re not doing complex multi-touch events, then the NSSet of touches will probably be sufficient Third, note that you’re sending the touches to the view controller by way of the nextResponder 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 reportView is the UIViewController We would have preferred to have the UIView-Controller just naturally respond to the touches messages, but we made use of our responder chain in the next best way As of this writing, the compiler warns that next-Responder may not know about the manageTouches method, but it will; this warning can be ignored
Listing 14.2 A collection of methods report touches in UIViews
UIViewController UIWindow
reportView UILabel UITextField UITextField
Figure 14.4 Working primarily in Interface Builder, we’ve connected up six objects that we’ll be using to report iPhone events.
Trang 9We’ll see some other ways to use the nextResponder method toward the end of our discussion of events.
AN ASIDE ON THE TEXT FIELDS AND LABEL
If you were to actually code in this example, you’d discover that this program correctly responds to touch events even when the touches occurred atop one of the text fields
or the label at the bottom of the page How does your program manage that when you only built event response into 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 get passed up the
responder chain to the reportView, which does leap on those events, using the code
we’ve just seen
14.2.3 Controlling your events
Intercepting touches and forwarding them up to the view controller may be the toughest part of this code Once the events get to the view controller, they run through a simple method called manageTouches:, as shown in listing 14.3
} else if (touch.phase == UITouchPhaseMoved) {
bottomLabel.text = @"Touch is moving ";
} else if (touch.phase == UITouchPhaseEnded) {
Listing 14.3 manageTouches, which accepts inputs and changes views
B
C
D E C C F
Trang 10Once 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 since we combined everything you have to fall back on the phase property Fortunately, it’s easy to use You just match it up to one of three con-stants C, and that determines which individual actions your program undertakes Having different responses based on the phase in which a touch arrive is com-mon—which is in fact why the event methods are split up in the first place Our exam-ple 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 bot-tom label in both the moved and ended phases.
In your UITouchPhaseBegan response, you delve further into your touch’s data by using the locationInView: method to figure out the precise coordinates where a touch occurred D You’re then able to use that data to reposition your text field and
to report the coordinates in the text field E You later do the same thing in the UITouchPhaseEnded response
Finally, you take a look at the tapCount in the UITouchPhaseEnded response F This is generally the best place to look at taps since the iPhone now knows that the user’s finger has actually 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 14.5 shows what your event responder
looks like in action You should imagine a finger that
set down on the space where the begin text field is
sit-ting and that is currently moving across the screen
And with that, your event reporter is complete
Besides illustrating how a program can respond to
touches, we have highlighted how the MVC model can
be used in a real application
Your project contained four views: a reportView, a
UILabel, and two UITextFields It was tempting to
process events in the reportView itself, especially since
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’d want to do MVC modeling
Since it takes on the controller role, you gave the
view controller access to all of its individual objects,
and therefore you didn’t have to try to remember
what object knew about what other object Tying
things into the view controller, rather than scattering
them randomly across your code, made your project
that much more readable and reusable, which is what
most architectural and design patterns are about
Figure 14.5 Your event responder uses a few graphical elements to report events as they occur.
Trang 1114.3 Other event functionality
Before we complete our discussion of events entirely, we’d like to cover a few more topics of interest We’re going to explore how to regulate the report of events in a vari-ety of ways and then describe some deficiencies in the event model
14.3.1 Regulating events
As we mentioned earlier, there are some ways that you can modify how events are reported (and whether they are at all) As you’ll see, three different objects give you access to this sort of regulation: UIResponder, UIView, and UIApplication We’ve listed all the notable options we’re going to discuss in table 14.4
Since UIView is a subclass of UIResponder, you’ll generally have access to the methods from both classes in most UIKit objects You’ll need to do some additional work to access the UIApplication methods
UIRESPONDER REGULATION
You’ve already seen that UIResponder is the source of the methods that let you ture events; as shown here, it’s also the home of the methods that control how the responder chain works
Most of the responder chain–related methods won’t be directly used by your code, instead typically appearing deep in frameworks becomeFirstResponder and
Table 14.4 Properties in various objects allow for additional control of when events are monitored.
Method or property Type Summary
method
Returns the next responder in the chain by default but can be modified
property
A Boolean set to NO by default; controls whether multi-touches after the first are thrown out
Trang 12resignFirstResponder (which control who the first responder is) and FirstResponder, canResignFirstResponder, and isFirstResponder (which return Booleans related to the information in question) all typically fall into this category It’s the last UIResponder method, nextResponder, which may be of use in your pro-grams As defined by UIResponder, nextResponder just returns the next responder, per the normal responder chain We used it in our example to pass our touches up.
If you want to change the normal order of the responder chain, you can do so by creating your own nextResponder function in a subclass This new function will over-ride its parent method, and thus will allow your program to take a different path up your own responder chain
exclusive-is an alternative way that we could have managed our eventreporter example, where
we didn’t want anything but the reportView to accept events) Meanwhile, TouchEnabled starts reporting of multi-touch events, which are otherwise ignored.UIAPPLICATION REGULATION
multiple-Finally we come to the UIApplication methods These lie outside of our normal archy of objects, and thus we can’t get to them from our view objects Instead we need
hier-to call them directly from the UIApplication object as shown here:
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
As you may recall from chapter 11, sharedApplication is a UIApplication class method that provides us with a reference to the application object Typically, we’ve used its return as the receiver for the beginIgnoringInteractionEvents message Each of the three methods listed under UIApplication works as you’d expect once you know the secret to accessing them
14.3.2 Other event methods and properties
We’ve spent a lot of time on events, but at the same time we’ve only scratched the face We have mixed feelings on the subject
On the one hand, events give you low-level access to the unique user input allowed
by the iPhone Since much of this book is about how the iPhone is unique, we’d like to delve into it much further
On the other hand, you won’t be using events that much That’s because you usually won’t need this sort of low-level control over your user input Instead, you’ll use the iPhone’s many control objects (and thus actions) in order to accept almost all user input
As a result, this chapter has offered you a compromise: a solid look at how events work that should suffice for those times when you do need to descend to touch management,