No buried point is also called full buried point or zero buried point, although the name is different, the purpose to achieve is the same, that is, data collection does not need hard code, and can even be dynamically configurable data to be collected. We will not discuss the details of the no-burying scheme here, but only a few points encountered in practice. At present, there is room for improvement in the scheme proposed in the online materials. Here is a concrete analysis.

1. Click event of UITableViewCell

UIKIT_EXTERN NSNotificationName const UITableViewSelectionDidChangeNotification;
Copy the code

Listening for notifications that are sent when the UITableViewCell is selected, as the name of the notification indicates, collects UITableViewCell selected events.

  1. UITableViewCell presents the event to uiKitCore. framework using class-dump to get a list of UITableView methods. The path to uikitCore. framework is/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes /iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/UIKitCore.framework/. You can also use Xcode to dump UITableView for more detailed information. The first configurationLLDB command, using the command
dclass -I UITableView
Copy the code

The following three methods are found by searching willDisplay:

-_createPreparedCellForGlobalRow:willDisplay:
-_createPreparedCellForRowAtIndexPath:willDisplay:
-_createPreparedCellForGlobalRow:withIndexPath:willDisplay:
Copy the code

Let’s look at the implementation of the three methods separately. Used here Hopper Disassembler, in the Hopper opened UIKitCore. The framework, such as analysis, search – _createPreparedCellForGlobalRow: willDisplay: and positioning, the code is as follows:

-_createPreparedCellForRowAtIndexPath:willDisplay:

-_createPreparedCellForGlobalRow:withIndexPath:willDisplay:

-tableView:willDisplayCell:forRowAtIndexPath:

3. Click and display UICollectionView Apply the above method to UICollectionView to find the corresponding method.

-_notifyWillDisplayCellIfNeeded:forIndexPath:
-_selectItemAtIndexPath:animated:scrollPosition:notifyDelegate:
Copy the code
  1. UIControl Click event
@interface UIApplication
- (BOOL)sendAction:(SEL)action to:(nullable id)target from:(nullable id)sender forEvent:(nullable UIEvent *)event;
Copy the code

Hook UIApplication method sendAction: to: the from: forEvent: can.

5.UITapGesture, UILongPressGesture

@interface UIApplication
- (void)sendEvent:(UIEvent *)event;
Copy the code

This method will distribute UI events in your app, so you need to filter out UIControl events. Then handle the Gesture event first. Record may be in touch when UITouchPhaseBegan corresponding gesture, find status to UIGestureRecognizerStatePossible gesture when UITouchPhaseEnded, It is the gesture that triggers. When recording gesture monitored gesture state at the same time, UILongPressGesture fires, state into UIGestureRecognizerStatePossible.

bool Click::handleGesture(UITouch *touch) {
  if (touch.phase == UITouchPhaseBegan) {
    bool handled = false;
    for (UIGestureRecognizer *obj in touch.gestureRecognizers) {
      if (obj.enabled) {
        observeGesture(obj);
        handled = true; }}return handled;
  } else if (touch.phase == UITouchPhaseCancelled) {
    if (observedGestures.count == 0) return false;
    for (UIGestureRecognizer *g in observedGestures) {
      objc_setAssociatedObject(g, kGestureObserverKey, nil, OBJC_ASSOCIATION_RETAIN);
    };
    [observedGestures removeAllObjects];
    return true;
  } else {
    return observedGestures.count > 0;
  }
}
bool Click::handleObserve(NSString *keyPath, NSObject *object, NSDictionary *change, void *context) {
  if ([keyPath isEqualToString:@"state"]) {
    if (IS(UIGestureRecognizer, object)) {
     auto gesture = (UIGestureRecognizer*)object;
     auto state = [(UIGestureRecognizer *)object state];
     auto handled = false;
     if (state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateFailed) {
          if (state == UIGestureRecognizerStateEnded) {
            handled = true;
          }
          objc_setAssociatedObject(object, kGestureObserverKey, nil, OBJC_ASSOCIATION_RETAIN);
        }
        [observedGestures removeObject:object];
      }
      returnhandled; }}return false;
}
Copy the code

The view of UIView ‘s property is considered a UIView’ s property, and if it is a subclass of UIView ‘s property, it can override its parent’ s property.