In the actual development will often encounter the operation of handling events, for us such a novice, will encounter one is when to deal with the event after the event occurs, the second is when the event processing will not get response and other problems; For this reason, it is necessary to have a clear understanding of how events occur, how they are delivered, and who is ultimately responsible for the response processing. Take the touch event as an example to elaborate:
This paper starts from the transmission of events, which is to solve the following problems:
- How do events arise?
- How are touch events that click on the screen transferred from the screen to the app?
- How the system passes click events to the window;
Related terms: touch, event, and responder
1. Touch: UITouch
Finger touching the screen produces the corresponding UItouch object, following the states of each stage of touch; Touch happens on the screen, it’s human;
2. Event: UIEvent
The purpose of touch is to generate touch events for the responder to respond to. A touch event corresponds to a UIEvent object, in which the Type attribute identifies the type of the event (events can be divided into many kinds, not just touch events). The UIEvent object contains a collection of touch objects that trigger the event, because a touch event can be generated by multiple fingers touching simultaneously. The collection of touch objects is retrieved via the allTouches property.
Here is the UIEventType, which identifies different events, including accelerator events, remote control events, movement events, rolling events, and so on.
3, responder: UIResponder
Not all objects in ios can receive events. Only objects that inherit from UIResponder can receive and handle events. These are called “responder objects”.
UIView, UIViewController, UIApplication, and Appdelegate responders can respond to events because UIResponder provides four methods for handling events:
From the above elaboration, it is clear that touch generates touch events, and the responder responds to the touch events. This understanding helps us to solve the first problem, how the event is generated. Similarly, taking the touch event as an example, when the screen is touched artificially, the system generates the corresponding UITouch object. After the UITouch object is created, a UITouch object corresponds to a UIEvent object. It produces what we call the corresponding touch event. The event is then passed to find the best responder object to respond to.
This still doesn’t solve our problem of how events are delivered, so move on.
How does the system pass click events to Windows?
When the user touches the screen, the corresponding touch event will be generated, and the event will be transmitted to the appropriate application through IPC interprocess communication. After the touch event is generated from the touch screen, IOKit passes the touch event to the SpringBoard process, which then distributes it to the current foreground APP for processing. Here is a simple flow chart for processing:
After passing the above process, our touch will be transferred to the corresponding APP or system desktop for processing; Here we will introduce the contents of runloop, runloop event loop mechanism, etc., which will be expanded later; All events are eventually added to the Runloop for processing;
Summary: When an external event (touch, shake, gravity, etc.) occurs, the IOKit. Framework first generates an IOHIDEvent event and sends it to SpringBord to receive. SpringBord received after the event, through the corresponding app MAC port forwarding to the current process, then apple registered the source1 will trigger the callback, and call the _UIApplicationHandleEventQueue () distribution within the application.
Related terminology concepts:
- IOKit is a collection of system frameworks used to drive system events; A library for receiving and processing hardware events, obtaining information about devices, etc. Here it is used to receive touch events and generate the corresponding IOHIDEvent object;
- HID in IOHIDEvent stands for Human Interface Device, namely human-computer interaction driver.
- Mach Port Indicates the process port through which processes communicate.
- Springboad. app is a system process that can be understood as a desktop system and can centrally manage and distribute touch events received by the system. (Not only touch events, SpringBoad receives buttons, touch, acceleration, gravity sensing, etc.);
From there, we have some answers to how an event is generated and transferred from user behavior to the window on the phone screen; So, the event will eventually be allocated to the desktop system or the corresponding APP process for processing, then, how to find the best event responder, and what is the transmission process inside the APP? The following:
3. Event transmission within App
Through the communication between the user touch screen and the IPC process, IOKit passes the touch event to the SpringBoard process, which is then distributed to the current foreground App for processing. At this point, the event reaches the App, the App process’s Mach port receives the touch event from the SpringBoard process, and the main thread’s runloop wakes up, triggering the source1 callback. The source1 callback triggers a source0 callback that encapsulates the received IOHIDEvent object as a UIEvent object, at which point the App formally begins responding to the touch event.
As shown in the figure below, events are transmitted within the App:
As shown in the figure above, the view level is A(B(D,E), C(G,F)) within the simulated app. Add B and C to A, D and E to B, and F and G to C;
Then, first: when the touch event occurs in the region where F is located, the event transmission and response process are as follows:
Determine whether it can respond to the event from four aspects :(allow interaction, no hiding, transparency, and the child view does not exceed the effective range of the parent view, that is, the click area);
- UIApplication first passes the event to A to determine whether it can respond to the event;
- If so, THEN A continues to pass the event to C (from back to forward query);
- C determines whether it can respond to the event. If so, C continues to send the event to G.
- G determines that it cannot respond to the event quickly. Then, G backs up to C, and C continues to transmit the event to F.
- F determines that it can respond to the event, and F has no subview, so F itself is the final responder of the event.
Second: When the touch event D occurs in the region where it is located and not in the scope of its parent view B, the event transmission and response process are as follows:
- UIApplication first passes the event to A to determine whether it can respond to the event;
- If so, then A continues to pass the event (from back to forward query);
- C determines whether it can respond to the event;
- C cannot respond to the event and falls back to A, where A continues to send the event to B.
- B determines whether it can respond to the event; Fall back to A;
- Back to A, A has no child views to pass events, so A is the final event responder; (Here’s the problem: if you don’t know the process, you might implement it thinking, “I’ve set the click event for D, so why does it sometimes respond to clicks when I click on the D control?” This means that when we can respond, our click area is in the region of the B superview where D is. When D does not respond, this is the case above;)
The above are two cases of event transmission, one is normal and the other is abnormal; In general, the transfer process of events in App is summarized as follows:
In other words, the transfer process of the event inside the App is to search continuously from the back to the front to find the best responder. The above process is the process from the event to find the best responder;
The transmission of events follows the following principles: peer transmission from back to front; So far, this article has done some talking about event generation and passing (see related section), so let’s verify with a simple example.
So, as mentioned above, there are four ways to determine whether the current view can respond to events:
- Whether to allow interaction: Set the userInteractionEnabled attribute of the responder object to NO, indicating that interaction is not allowed. YES indicates that interaction is allowed.
- Hidden: hidden = YES; If the parent view is hidden, the child view is also hidden, and the hidden view cannot receive events; Hidden = NO, not hidden;
- If you set the transparency of a view to <0.01, it directly affects the transparency of its subviews. Alpha: 0.0 to 0.01 is transparent.
- Whether the child view exceeds the valid scope of the parent view;
In the process of event transmission, the above judgments need to be made every time it passes through a view. Then, how does the app make these judgments inside? Therefore, one method must be mentioned: the hitTest method;
4. HitTest method
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
HitTest is a method in UIView. Each responder object has a corresponding hitTest method that determines whether it can respond to an event and pass the event.
The following is the hitTest judgment logic given above:
So hitTest does two things:
- One is used to query the responder of the event in the current view, and returns the responder object of the event that finally responded to this;
- Second, a bridge of event transmission;
This section concludes:
This section introduces the related content of event transmission from the occurrence of the event, how the event is transferred from the screen to the window, and the process of event transmission inside the APP. Answer the questions at the beginning of the passage. At the same time in the process of event transmission is a very important method hitTest method, to do a simple description of it.
Review questions:
- How did the event come about?
- How do events get from the screen to the window?
- Iii. The transmission process of events inside the App?
Supplementary question: When an event is found to be unresponsive during code implementation, which aspects should we look for?
Simple self-study for beginners.