详解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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。