What Happens when the User Taps on Screen?
Mar 20th, 2025I was recently asked this question in an iOS engineer interview. Instead of the simple answer regarding responder chain, the interviewer requested the answer to be as detailed as possible. After the interview, I digged through internet archives, UIKit documentation as well as answers from ChatGPT to look for information, and this is an revisited version of my answer to the question “What happens when the User Taps on Screen?”

Step 0: Before the Touch Events
Before the touch events start and during view initialization (usually in viewDidLoad), target-action pairs are registered and stored for later user.
-
AddGestureRecognizeris called, and the target-action pair is registered and stored in an internal array as part of theUIGestureRecognizerclass -
addTarget(:action:for)is called, and the target-action pair is registered and stored in theUIControlclass
Step 1: Touch Events are Detected
Physical Interaction: Hardware Detects the Touch
-
The screen (digitizer) detects the user’s finger or Apple Pencil Movement
-
Electronic signals are generated and converted into digital data (raw touch points), and sent to the device’s Touch Controller
-
The Touch Controller analyzes signals to determine precise touch points, pressure, and even multiple touches if applicable.
Low-level Processing: Touch event is sent to iOS kernel
-
The iOS kernel processes the raw touch data from the hardware.
-
Converts raw data into multi-touch events, identifying gestures like taps, swipes, etc.
-
The kernel associates a timestamp with the touch event, which helps order multiple touch events accurately.
UIKit Processing: Event is forwarded to UIApplication via Run Loop
-
The iOS kernel packages the touch data into a
UIEventobject and sends it to the main run loop. -
The
UIApplicationinstance (managed byUIApplicationMain()) picks up the event and initiates event-dispatching.
Hit testing: Event is sent to the active UIWindow
-
The
UIWindowreceives theUIEventfromUIApplication. -
The window asks the root view controller to perform hit-testing by calling
hitTest(_:with:)on the root view. -
hitTest(_:with:)starts from the root view and recursively traverses all subviews in reverse drawing order (top-most drawn view first). -
The traversal continues until a view returns itself as the hit view or
nilif not found.-
hitTestcould returnnilwhen:-
The user taps on a transparent area (
isUserInteractionEnabled = false). -
The view has
isHidden = true. -
The view has
alpha = 0.0.
-
-
Passing Event to Responder Chain
- Once a
UIViewis identified, UIKit passes the event through the responder chain to the targetUIView.
Step 2: UIEvent Handling Begins
Check for Gesture Recognizers
- If the view has a
UIGestureRecognizer, it gets the first chance to handle the touch. The gesture recognizer decides whether to intercept the touch or let the view handle it.
UIView handling
-
touchesBegan(_:with:)- Called when a touch begins. -
touchesMoved(_:with:)- Called when the touch moves. -
touchesEnded(_:with:)- Called when the user lifts their finger. -
touchesCancelled(_:with:)- Called if the system interrupts the touch (e.g., incoming call).
UIControl Handling:
Assuming the view is a UIButton and the event is .touchUpInside:
-
UIKitdetects.touchUpInsideand sends the event to theUIButtoninstance -
UIButtoncheck the internal target-action mapping-
if found:
-
By default
UIButtoncallsUIControl.sendAction(_:to:for:)to trigger the handler locally -
However, if the target is nil,
UIButtoncallsUIApplication.shared.sendAction(_:to:from:for:)to propagate the event up the response chain- If not found, the event is not handled.
-
-
Event Propagation (Responder Chain)
-
If the view does not handle the event,
UIKitpass it up the responder chain; -
If no object handles the event,
UIKitdiscards it.
Step 3: Triggers an Action
Objc Runtime Handling
-
The target’s selector function (
@objc func buttonTapped()) executes. -
The Objective-C runtime uses
objc_msgSendto invoke the method on the target. (objc_msgSend(target, action, self)). GCD/Run Loop ensures the method is called on the correct thread (eg. main thread for UI-related actions).-
The method is called synchronously within the current run loop cycle and returns control to the run loop upon completion.
-
Once the function returns, control goes back to the UIKit event loop. UIKit marks the event as handled. The event does not propagate further in the responder chain.
-
UIKitfinishes processing the touch event
-
Step 4: UI Update (If Needed)
UIKitschedules the UI updates on the main thread. Views are updated on the next run loop cycle.
Step 5: Completion
-
Main thread resumes,
UIKitresumes handling other events -
After all processing,
UIKitreturns to idle mode, waiting for the next user interaction.