详解iOS按钮暴力点击的便捷解决方案
iOS点击事件分类
1.程序中大量按钮没有做连续响应的校验,测试人员连续点击出现了很多不必要的问题,所以只能利用运行时特性,进行hook一下。runtime不能大量使用,但是偶尔使用也是很方便的哈哈。
2.设置单个按钮不需要hook
3.多次点击按钮,只执行最后一次点击事件,忽略前面的点击时间
////UIButton+touch.h //LiqForDoctors #import#definedefaultInterval.5//默认时间间隔 @interfaceUIButton(touch) /**设置点击时间间隔*/ @property(nonatomic,assign)NSTimeIntervaltimeInterval; @end
// //UIButton+touch.m //LiqForDoctors // #import"UIButton+touch.h" @interfaceUIButton() /**bool类型YES不允许点击NO允许点击设置是否执行点UI方法*/ @property(nonatomic,assign)BOOLisIgnoreEvent; @end @implementationUIButton(touch) +(void)load{ staticdispatch_once_tonceToken; dispatch_once(&onceToken,^{ SELselA=@selector(sendAction:to:forEvent:); SELselB=@selector(mySendAction:to:forEvent:); MethodmethodA=class_getInstanceMethod(self,selA); MethodmethodB=class_getInstanceMethod(self,selB); //将methodB的实现添加到系统方法中也就是说将methodA方法指针添加成方法methodB的返回值表示是否添加成功 BOOLisAdd=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)actionto:(id)targetforEvent:(UIEvent*)event { if([NSStringFromClass(self.class)isEqualToString:@"UIButton"]){ self.timeInterval=self.timeInterval==0?defaultInterval:self.timeInterval; if(self.isIgnoreEvent){ return; }elseif(self.timeInterval>0){ [selfperformSelector:@selector(resetState)withObject:nilafterDelay:self.timeInterval]; } } //此处methodA和methodB方法IMP互换了,实际上执行sendAction;所以不会死循环 self.isIgnoreEvent=YES; [selfmySendAction:actionto:targetforEvent: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{ [selfsetIsIgnoreEvent:NO]; } @end
demo下载:demo
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。