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


Related articles: