Explain the convenient solution of violent click of iOS button in detail
- 2021-09-16 08:17:57
- OfStack
iOS Click Event Classification
1. A large number of buttons in the program have not been verified for continuous response, and there are many unnecessary problems when testers click continuously, so they can only use the runtime characteristics to perform hook1. runtime can't be used in large quantities, but it is very convenient to use it occasionally.
2. Setting a single button does not require hook
3. Click the button several times, only execute the last click event, ignoring the previous click time
//// UIButton+touch.h
// LiqForDoctors
#import#define defaultInterval .5 // Default time interval
@interface UIButton (touch)
/** Set the click interval */
@property (nonatomic, assign) NSTimeInterval timeInterval;
@end
//
// UIButton+touch.m
// LiqForDoctors
//
#import "UIButton+touch.h"
@interface UIButton()
/**bool Type YES No clicks allowed NO Allow clicks Set whether to execute point or not UI Method */
@property (nonatomic, assign) BOOL isIgnoreEvent;
@end
@implementation UIButton (touch)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selA = @selector(sendAction:to:forEvent:);
SEL selB = @selector(mySendAction:to:forEvent:);
Method methodA = class_getInstanceMethod(self,selA);
Method methodB = class_getInstanceMethod(self, selB);
// Will methodB Implementation of Add to a system method That is to say Will methodA Method pointer is added to the Method methodB Adj. The return value indicates whether the addition was successful
BOOL isAdd = class_addMethod(self, selA, method_getImplementation(methodB), method_getTypeEncoding(methodB));
// The addition succeeded Description Does not exist in this class methodB So at this time, you must put the method b Replace the implementation pointer with the method of A Otherwise, b Method will not be implemented.
if (isAdd) {
class_replaceMethod(self, selB, method_getImplementation(methodA), method_getTypeEncoding(methodA));
}else{
// Add failed Explain that in this class Have methodB At this time, you only need to set the implementation of methodA And methodB Adj. IMP Interchange 1 Just go down.
method_exchangeImplementations(methodA, methodB);
}
});
}
- (NSTimeInterval)timeInterval
{
return [objc_getAssociatedObject(self, _cmd) doubleValue];
}
- (void)setTimeInterval:(NSTimeInterval)timeInterval
{
objc_setAssociatedObject(self, @selector(timeInterval), @(timeInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
// When we click the button event sendAction Hour Will execute mySendAction
- (void)mySendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
if ([NSStringFromClass(self.class) isEqualToString:@"UIButton"]) {
self.timeInterval =self.timeInterval ==0 ?defaultInterval:self.timeInterval;
if (self.isIgnoreEvent){
return;
}else if (self.timeInterval > 0){
[self performSelector:@selector(resetState) withObject:nil afterDelay:self.timeInterval];
}
}
// Here methodA And methodB Method IMP Interchangeable, actually executed sendAction ; So there will be no infinite loop
self.isIgnoreEvent = YES;
[self mySendAction:action to:target forEvent:event];
}
//runtime Dynamic binding Attribute
- (void)setIsIgnoreEvent:(BOOL)isIgnoreEvent{
// Attention BOOL Type Need to use OBJC_ASSOCIATION_RETAIN_NONATOMIC Don't use it wrong, otherwise set Method will make an error in assignment
objc_setAssociatedObject(self, @selector(isIgnoreEvent), @(isIgnoreEvent), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)isIgnoreEvent{
//_cmd == @select(isIgnore); And set In the method 1 To
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
- (void)resetState{
[self setIsIgnoreEvent:NO];
}
@end
demo Download: demo