开发过程中,总是遇到按钮连续点击后,多次触发事件,导致程序奔溃或者体验差,需要我们禁止按钮的连续点击事件,当然我们可以使用属性userInteractionEnabled来设置是否支持交互.点击后设置为NO,事件处理完毕后设置为YES,这样是可以满足需求的.当然还可使用performSelector:withObject:afterDelay:和cancelPreviousPerformRequestsWithTarget两个方法,同样也可达到效果!
不多说什么,我们主要说说Runtime方式解决这个问题的方法!上代码:
我们创建UIButton的一个分类,这样就可以为所有的按钮添加
-
UIButton+touchInterval.h
#import <UIKit/UIKit.h> #define defaultInterval .7// 默认间隔时间 @interface UIButton (touchInterval) /** * 设置点击时间间隔 */ @property (nonatomic, assign) NSTimeInterval timeInterVal; @end
-
UIButton+touchInterval.m
#import "UIButton+touchInterval.h" #import <objc/runtime.h> @interface UIButton () /** * BOOL 设置是否执行触及事件方法 */ @property (nonatomic, assign) BOOL isExecuteEvent; @end @implementation UIButton (touch) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //方法选择器 SEL oldSel = @selector(sendAction:to:forEvent:); SEL newSel = @selector(wm_sendAction:to:forEvent:); // 获取到响应者链事件分发方法 Method oldMethod = class_getInstanceMethod(self, oldSel); // 获取到上面新建的newsel方法 Method newMethod = class_getInstanceMethod(self, newSel); // IMP 指方法实现的指针,每个方法都有一个对应的IMP, //调用方法的IMP指针避免方法调用出现死循环问题 BOOL isAdd = class_addMethod(self, oldSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); if (isAdd) { // 将newSel替换成oldMethod class_replaceMethod(self, newSel, method_getImplementation(oldMethod), method_getTypeEncoding(oldMethod)); }else{ // 给两个方法互换实现 method_exchangeImplementations(oldMethod, newMethod); } }); } - (void)wm_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { if ([NSStringFromClass(self.class) isEqualToString:@"UIButton"]) { if (!self.isExecuteEvent) { //设置点击间隔时间,如果未设置,默认为defaultInterval=0.7 self.timeInterVal = (self.timeInterVal == 0? defaultInterval:self.timeInterVal); } if (self.isExecuteEvent) { //如果是YES,则不发送事件消息 return; } if (self.timeInterVal > 0) { //在设置的时间内isExecuteEvent为YES self.isExecuteEvent = YES; //在设置的间隔时间后重新设置isExecuteEvent为NO [self performSelector:@selector(setIsExecuteEvent:) withObject:nil afterDelay:self.timeInterVal]; } } //在时间间隔内,isExecuteEvent为YES,不会调用此方法 [self wm_sendAction:action to:target forEvent:event]; } static const char *UIButton_timeInterValKey = "UIButton_timeInterVal"; - (NSTimeInterval)timeInterVal { // 动态获取关联对象 return [objc_getAssociatedObject(self, UIButton_timeInterValKey) doubleValue]; } - (void)setTimeInterVal:(NSTimeInterval)timeInterVal { // 动态设置关联对象 objc_setAssociatedObject(self, UIButton_timeInterValKey, @(timeInterVal), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } static const char *UIButton_isExecuteEventKey = "UIButton_isExecuteEvent"; - (void)setIsExecuteEvent:(BOOL)isExecuteEvent { // 动态设置关联对象 objc_setAssociatedObject(self, UIButton_isExecuteEventKey,@(isExecuteEvent), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (BOOL)isExecuteEvent { // 动态获取关联对象 return [objc_getAssociatedObject(self, UIButton_isExecuteEventKey) boolValue]; } @end
我们使用时,只需要设置我们想要的时间间隔即可,如果不设置时间间隔,那么默认间隔时间为defaultInterval = 0.7