The problem

  1. whenUIControlAdded to an object with a gestureUIViewAnd to giveUIControladdedtarget-action, then it will be executedUIControltarget-actionorUIView“?

I believe that this seems like an easy first question, at least 90% of iOSer will get it wrong.

Who responds to events

All subclasses that inherit from UIResponder

UIButton, UIView, UIWindow, UIApplication, etc…

What is an event

Touch, shake, etc

Graph TD finger touch screen --> IOKit. Framework encapsulates IOHIDEvent object --> forward to SprintBoard via MachPort --> forward to main thread of current APP via MachPort

RunLoop

  1. The main threadRunLoopSource1Trigger, triggerSource1The callback:__IOHIDEventSystemClientQueueCallback()
  2. Source1The triggerSource0The callback:__UIApplicationHandleEventQueue()That will beIOHIDEventEncapsulated in theUIEvent
  3. Source0Is called internallyUIApplicationsendEventUIEventTo pass toUIWindow

Determine who is the first responder

  1. Check whether hidden, transparent, interoperable, none
  2. Determines whether the click is in the view
  3. If in, toFILOTo find whether the subview is in the click range
  4. If not, check to see if it is in the peer view

The code is as follows:

 override func hitTest(_ point: CGPoint.with event: UIEvent?). -> UIView? {
        print(classTag, #function, self.point(inside: point, with: event))
        if isHidden || !isUserInteractionEnabled || alpha < = 0.01 {
            return nil
        }
        if self.point(inside: point, with: event) {
            for subview in subviews.reversed() {
                let convertedPoint = subview.convert(point, from: self)
                let resultView = subview.hitTest(convertedPoint, with: event)
                if let resultView = resultView {
                    return resultView
                }
            }
            return self
        }
        return super.hitTest(point, with: event)
    }
Copy the code

Passing events along the response chain

Identify the members of the response chain

First responder -> First Responder parent view -> Parent view of the parent view -> UIViewController -> UIWindow -> UIApplication

A nextResponder is a superView

A method for passing events

func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?).
func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?).
func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?).
func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?).
Copy the code

If the above method’s super is called, the event will still be passed, otherwise it will not be passed

When gesture recognition participates in the response chain

And the response chain

cancelsTouchesInView

The default is true. If set to false, touchesCancelled will not be sent to the target view. The result is that both the gesture and the method fire at the same time.

delaysTouchesBegan

The default is false. When set to true, a ‘touchesBegan’ is delayed until gesture recognition fails.

delaysTouchesEnded

The default is true. If set to false, touchesEnd will be triggered immediately; gestures like double clicking will not be triggered.

UIControl and gesture recognition

  1. UIControlusetarget-actionRespond to the event and no longer pass the event down the response chain.
  2. UIControltarget-actionThe trigger time was whentouchesEndAfter.
  3. And this one above will cause, if there’s a gesture on the superview,UIControlWill not be able to executetarget-action.So the answer above is to perform the superview gesture, notUIControltarget-action.
  4. iftarget-actiontargetnil, this will be changedactionThe extended response chain is passed down until it is discarded
  5. iftarget-actiontargetselfWould go,runtimeMessage forwarding, if none is eventually found, is reportedunrecgnize selectorThe exception.

Reference:

IOS | events and response chain

IOS | response chain and gesture recognition