October 3, 2010 1

Post-A-Day #8 – Allow superview to recieve events caught by subview.

By admin in iOS

I had a problem in my current project related to this, and it was a good opportunity, to learn a little bit more about how touches are handled in iOS.

Enter UIResponder

UIResponder is the Class any objects that which to receive events must Subclass, if they wish to receive (among other types) TouchEvents from the application.
UIView and UIViewController are two distinct Subclasses of UIResponder. However keep in mind that UIViewController is not a subclass of UIView, nor is UIView a subclass of UIViewController. Each is distinct.

For the purposes of this discussion, just know that it implements these four methods.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

The responder chain

All active UIResponders are actually part of the ‘ResponderChain‘ . In other words; each one knows about the next one in the ResponderChain. This is probably done this way to to run as fast as possible during RunTime.

The tail of the responder chain, for applications running on iOS is the UIWindow.
When a user taps the screen, the device figures out who to call ‘touchesBegan‘ on by calling –hitTest:withEvent: on all active responders. This function in turn calls, –pointInside:withEvent: on of that views subviews.

So if you had objectA, inside of objectB, which is inside of objectC. Actually let’s use a more concrete example: imagine you had Person, inside of a House, inside of Block.
In our pseudo real world example the responder chain might look like this: Person->House->Block->…->Universe.
When a user touches the screen, PersonA is the head of the responder chain, he checks if the tap happened on him by checking ‘pointInside:withEvent:’, if the response is NO. The next object in the ResponderChain, in our case House does the same check. Eventually if no one caught the TouchEvent, the universe receives it and can do something with it or nothing.

The way apple has implemented the ResponderChain actually makes it much simpler to ‘bubble up’ a touch event however.
To bubble up a touch event from a subView to it’s parentView, you simply call -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; you simply call on super. For example:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
     // Forward this message up the responder chain
     [super touchesBegan:touches withEvent: event];


One Response to “Post-A-Day #8 – Allow superview to recieve events caught by subview.”

  1. Al says:

    You only need to call [super touchesBegan:touches withEvent: event] if you need to handle the event in both the subview and the superview.

    The event will ‘bubble up’ on its own without calling [super touchesBegan:withEvent] as long you have no implementation of – (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event in the subview.

    So in the code bit you show above, it would be unnecessary; you could delete the entire thing and the event will still get fired in the superview!

Leave a Reply

Powered by WP Hashcash

Spam protection by WP Captcha-Free