“This is the 13th day of my participation in the November Gwen Challenge. See details: The Last Gwen Challenge 2021”.
Gesture Has a system for single-player double-clicking, so you don’t have to customize the interval. I’m only dealing with UIButton, UITableView
1. Ideas:
UIButton hook sendAction
UITableView hook setDelegate(swift doesn’t have this method, use OC instead)
Gesture hook initWithTarget:action:
1, Hook button sendAction hook UIControl sendAction, click UIControl subclass (navigation back button) will crash. Therefore, change UIButton hook to UIControl hook. In order to avoid impact on other UIControl subclasses (UISlider/UISwitch), the function to prevent repeated clicks is disabled by default
[_UIButtonBarButton xx_sendActionWithAction:to:forEvent:]: unrecognized selector sent to instance 0x7f8e2a41b380'
The method 2, OC is NSDate. Date. TimeIntervalSince1970, not [[NSDate date] timeIntervalSince1970]
3. Since the setDelegate method can be called multiple times, determine if it is already swizzling to prevent repeated execution. SetDelegate calls method_exchange twice after base class A hooks A tableView… (didSelectRowAtIndexPath). When the base class is UITableViewController, it has no impact. When the base class is VC with UITableView, subclass A is normal and subclass B is abnormal. Solution 1: didSelectRow does not write it in the base class, does it in the subclass, or does it in the base class but does it in the subclass. Solution 2: Safer runtime method interchange library Aspects.
2, code,
+(void)load{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ SEL originalAppearSelector = @selector(setDelegate:); SEL swizzingAppearSelector = @selector(my_setDelegate:); method_exchangeImplementations(class_getInstanceMethod([self class], originalAppearSelector), class_getInstanceMethod([self class], swizzingAppearSelector)); }); } -(void)my_setDelegate:(id<UITableViewDelegate>)delegate{ [self my_setDelegate:delegate]; SEL sel = @selector(tableView:didSelectRowAtIndexPath:); SEL sel_t = @selector(my_tableView:didSelectRowAtIndexPath:); / / if you don't realize the tableView: didSelectRowAtIndexPath: there is no need to hook the if (! [delegate respondsToSelector:sel]){ return; } BOOL addsuccess = class_addMethod([delegate class], sel_t, method_getImplementation(class_getInstanceMethod([self class], sel_t)), nil); // If it is successfully added, it is implemented directly. If it is not successfully added, If (addSuccess) {Method selMethod = class_getInstanceMethod([delegate class], sel); Method sel_Method = class_getInstanceMethod([delegate class], sel_t); method_exchangeImplementations(selMethod, sel_Method); }} // Since we swapped methods, when the tableView's didSelected is called, the following methods are called: -(void)my_tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ If (NSDate. Date. TimeIntervalSince1970 - tableView. AcceptEventTime < tableView. AccpetEventInterval) {NSLog (@ "click too fast"); return; } if (tableView.accpetEventInterval > 0) { tableView.acceptEventTime = NSDate.date.timeIntervalSince1970; } [self my_tableView:tableView didSelectRowAtIndexPath:indexPath]; }Copy the code
3, attention points, risk points
If the current class does not implement the swapped method and the parent class implements the case, the implementation of the parent class will be swapped. If multiple inheritors of the parent class are swapped, the method will be swapped for many times and chaos. At the same time, when the method of the parent class is called, it will crash because it cannot be found. Should try before the exchange for the current class added for the exchange of the function of the new implementation IMP, if add success shows class does not implement the exchange method, then only need to replace the realization of the classification exchange methods for the realization of the original method, if add failed, was the original class implements exchange method, can be directly exchanged.
2. Load sequence and interaction of load methods
A class B might inherit super class A, and it might have its own class C. If the load methods are also implemented in the class, what is the order in which they are called? The system will call the super load method first, then call the load method of class B itself, and then call the load method of class C of class B. That is to say, all the load methods in the inheritance chain including the load method in the class extension will be executed, but the execution order needs to be paid attention to. The load method is different from other override methods in the classification. If other methods in class B are overridden in class C, they will be executed in class C first. But load is different, because that’s how the class load setup works.
3, the problem is difficult to check the text long press – edit – copy or cut click events, need to filter right swipe delete case: sendAction method will be called twice quickly