首页 > 系统 > iOS > 正文

详解iOS按钮暴力点击的便捷解决方案

2020-07-26 02:59:52
字体:
来源:转载
供稿:网友

iOS点击事件分类

1.程序中大量按钮没有做连续响应的校验,测试人员连续点击出现了很多不必要的问题,所以只能利用运行时特性,进行hook一下。runtime不能大量使用,但是偶尔使用也是很方便的哈哈。

2.设置单个按钮不需要hook

3.多次点击按钮,只执行最后一次点击事件,忽略前面的点击时间

//// UIButton+touch.h// LiqForDoctors#import#define defaultInterval .5 //默认时间间隔@interface UIButton (touch)/**设置点击时间间隔*/@property (nonatomic, assign) NSTimeInterval timeInterval;@end
//// UIButton+touch.m// LiqForDoctors//#import "UIButton+touch.h"@interface UIButton()/**bool 类型 YES 不允许点击 NO 允许点击 设置是否执行点UI方法*/@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);  //将 methodB的实现 添加到系统方法中 也就是说 将 methodA方法指针添加成 方法methodB的 返回值表示是否添加成功  BOOL isAdd = class_addMethod(self, selA, method_getImplementation(methodB), method_getTypeEncoding(methodB));  //添加成功了 说明 本类中不存在methodB 所以此时必须将方法b的实现指针换成方法A的,否则 b方法将没有实现。  if (isAdd) {   class_replaceMethod(self, selB, method_getImplementation(methodA), method_getTypeEncoding(methodA));  }else{   //添加失败了 说明本类中 有methodB的实现,此时只需要将 methodA和methodB的IMP互换一下即可。   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);}//当我们按钮点击事件 sendAction 时 将会执行 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];  } } //此处 methodA和methodB方法IMP互换了,实际上执行 sendAction;所以不会死循环 self.isIgnoreEvent = YES; [self mySendAction:action to:target forEvent:event];}//runtime 动态绑定 属性- (void)setIsIgnoreEvent:(BOOL)isIgnoreEvent{ // 注意BOOL类型 需要用OBJC_ASSOCIATION_RETAIN_NONATOMIC 不要用错,否则set方法会赋值出错 objc_setAssociatedObject(self, @selector(isIgnoreEvent), @(isIgnoreEvent), OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (BOOL)isIgnoreEvent{ //_cmd == @select(isIgnore); 和set方法里一致 return [objc_getAssociatedObject(self, _cmd) boolValue];}- (void)resetState{ [self setIsIgnoreEvent:NO];}@end

demo下载:demo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表