This is the sixth day of my participation in the First Challenge 2022. For details: First Challenge 2022.

preface

IOS response chain is the response basis of APP interaction. Only subclasses of UIResponder can trigger the response mechanism.

UIResponder is an iOS API for handling user events. It handles touch events using the following methods

// touch started - (void)touchesBegan:(NSSet< uittouch *> *)touches withEvent:(nullable UIEvent *)event; // touch moved - (void)touchesMoved:(NSSet< uittouch *> *)touches withEvent:(nullable UIEvent *)event; // touches are cancelled (before the touch ends) // a system event (such as a phone call) interrupts touches - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event; // end of touches - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;Copy the code

For touch events, the system provides the above four methods to handle. If the above method is overridden, the event breaks here and is no longer passed along the event response chain; If you need to continue passing, you need to call the super method.

The response mechanism mainly consists of transfer chain and response chain

Event passing mechanism

Delivery chain: Event delivery starts with UIApplication management and moves down the hierarchy.

UIApplication -> UIWindow -> root View -> subView -> First View

  1. When a touch event occurs in an iOS application, the system adds the event to a task queue managed by UIApplication
  2. UIApplication dispatches down events that are at the top of the task queue. The UIWindow.
  3. UIWindow distributes events down, UIView.
  4. UIView first looks at whether it can handle the event, whether the touch point is on it. If so, continue looking for subviews.
  5. Iterate through the child control, repeating steps 3 and 4. If you do not find a touch point in a child control, you are the event handler.
  6. If you can’t handle the touch response yourself, do nothing.

Several cases of event distribution are left untreated

  1. Alpha < 0.01
  2. userInteractionEnabled = NO
  3. hidden = YES

If the parent view event is not handled, then the child view will not pass the event, and the event passing is deprecated.

There are two core approaches to event passing:

// The view returned by this method is the best view needed for this click event, The view used to find the final response - (UIView*) hitTest:(CGPoint)point withEvent:(UIEvent *)event // determines whether a point is within the scope of the view - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 1. By overriding the hitTest method, you can move the clicked point to a child view. 2. Rewrite the pointInside method to enlarge the click area of the button. eg: The click area of the button should be rewritten to be less than 44*44. The following example defines the clickable region of a button - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {CGRect bounds = self.bounds;  CGFloat widthDelta = MAX(44 - bounds.size.width, 0); CGFloat heightDelta = MAX(44 - bounds.size.height, 0); Bounds = CGRectInset(Bounds, -0.5 * widthDelta, -0.5 * heightDelta); return CGRectContainsPoint(bounds, point); }Copy the code

The hitTest:withEvent: method is handled as follows:

  1. Through the firstpointInside:withEvent:Method to determine whether the current touch point is in the current view. If NO is returned, it terminates.hitTest:withEvent:Returns nil.
  2. If you return YES, you can either continue down and send to all children of the current viewhitTest:withEvent:Message, all subviews are traversed from the topmost view to the bottom view, i.e. from the end of the subviews array, until any subviews return non-empty objects or all subviews are traversed.
  3. If a subview returns a non-empty object, this object is returned, and the processing is complete. (The subview judgment process is also passedpointInside:withEvent:Judgmental).
  4. If all thesubviewIf no non-empty object is returned at the end of the traversal, thenhitTest:withEvent:Return self.

Event response mechanism

Response chain: The response chain passes from the bottom up. The response chain is a linked list formed by the nextResponder attribute. The view clicked has a superView, and the nextResponder is the superView.

First View -> Super View -> View Controller -> Window -> Application -> AppDelegate

  1. First responder found by event passing.
  2. If the VIEW’s VC exists, the event is passed to its VC response; If not, it is passed to its parent view.
  3. If the top-level view cannot handle the event, it is passed to UIWindow for processing.
  4. If UIWindow can’t handle it, pass it to UIApplication.
  5. If UIApplication cannot handle it, the event is discarded.