├── UIButton-touch ├── UIButton+Delay.h ├── UIButton+touch.h ├── UIButton+Delay.m └── UIButton+touch.m └── README.md /UIButton-touch/UIButton+Delay.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+Delay.h 3 | // Test001 4 | // 5 | // Created by StriEver on 16/4/18. 6 | // Copyright © 2016年 StriEver. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIButton (Delay) 12 | /**设置点击时间间隔*/ 13 | @property (nonatomic, assign) NSInteger delayInterval; 14 | @property (nonatomic, strong) dispatch_source_t timer; 15 | @property (nonatomic, assign) BOOL isNeedDelay; 16 | @end 17 | -------------------------------------------------------------------------------- /UIButton-touch/UIButton+touch.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+touch.h 3 | // LiqForDoctors 4 | // 5 | // Created by StriEver on 16/3/10. 6 | // Copyright © 2016年 iMac. All rights reserved. 7 | // 8 | 9 | #import 10 | #define defaultInterval .5 //默认时间间隔 11 | @interface UIButton (touch) 12 | /**设置点击时间间隔*/ 13 | @property (nonatomic, assign) NSTimeInterval timeInterval; 14 | /** 15 | * 用于设置单个按钮不需要被hook 16 | */ 17 | @property (nonatomic, assign) BOOL isIgnore; 18 | @end 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #UIButton+touch category # 2 |
    3 |
  1. When the button Clicked continuously,this category will be helpful。The button only response for the first event and then will ignore the remaining。We can customize the time interval
  2. 4 |
  3. When a button dones't hook this, wo need set the button Property ‘isIgnore' true
  4. 5 |
  5. Use UIButton+delay.The button only response for the last event and then will ignore the remaining。We can also customize the time interval
  6. 6 |
7 | 8 | -------------------------------------------------------------------------------- /UIButton-touch/UIButton+Delay.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+Delay.m 3 | // Test001 4 | // 5 | // Created by StriEver on 16/4/18. 6 | // Copyright © 2016年 StriEver. All rights reserved. 7 | // 8 | 9 | #import "UIButton+Delay.h" 10 | #import 11 | #define defaultInteral @"1" 12 | @implementation UIButton (Delay) 13 | - (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{ 14 | if (!self.isNeedDelay) { 15 | [super sendAction:action to:target forEvent:event]; 16 | return; 17 | } 18 | self.delayInterval = [defaultInteral integerValue] ; //倒计时时间 19 | if (self.timer) { 20 | dispatch_source_cancel(self.timer); 21 | self.timer = nil; 22 | 23 | } 24 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 25 | if (!self.timer) { 26 | self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue); 27 | } 28 | dispatch_source_set_timer(self.timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); 29 | dispatch_source_set_event_handler(self.timer, ^{ 30 | if(self.delayInterval==0){ //倒计时结束,关闭 31 | dispatch_source_cancel(self.timer); 32 | self.timer = nil; 33 | [super sendAction:action to:target forEvent:event]; 34 | self.delayInterval = [defaultInteral integerValue]; 35 | }else{ 36 | [super sendAction:@selector(handleAction:) to:self forEvent:event]; 37 | self.delayInterval--; 38 | } 39 | }); 40 | dispatch_resume(self.timer); 41 | 42 | } 43 | - (void)handleAction:(id)sender { 44 | 45 | } 46 | - (NSInteger)delayInterval{ 47 | return [objc_getAssociatedObject(self, _cmd) integerValue]; 48 | } 49 | - (void)setDelayInterval:(NSInteger)delayInterval{ 50 | objc_setAssociatedObject(self, @selector(delayInterval), @(delayInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 51 | 52 | } 53 | - (dispatch_source_t)timer{ 54 | return objc_getAssociatedObject(self, _cmd); 55 | } 56 | - (void)setTimer:(dispatch_source_t)timer{ 57 | objc_setAssociatedObject(self, @selector(timer),timer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 58 | 59 | } 60 | - (void)setIsNeedDelay:(BOOL)isNeedDelay{ 61 | // 注意BOOL类型 需要用OBJC_ASSOCIATION_RETAIN_NONATOMIC 不要用错,否则set方法会赋值出错 62 | objc_setAssociatedObject(self, @selector(isNeedDelay), @(isNeedDelay), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 63 | } 64 | - (BOOL)isNeedDelay{ 65 | //_cmd == @select(isIgnore); 和set方法里一致 66 | return [objc_getAssociatedObject(self, _cmd) boolValue]; 67 | } 68 | @end 69 | -------------------------------------------------------------------------------- /UIButton-touch/UIButton+touch.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+touch.m 3 | // LiqForDoctors 4 | // 5 | // Created by StriEver on 16/3/10. 6 | // Copyright © 2016年 iMac. All rights reserved. 7 | // 8 | 9 | #import "UIButton+touch.h" 10 | #import 11 | @interface UIButton() 12 | /**bool 类型 YES 不允许点击 NO 允许点击 设置是否执行点UI方法*/ 13 | @property (nonatomic, assign) BOOL isIgnoreEvent; 14 | @end 15 | @implementation UIButton (touch) 16 | + (void)load{ 17 | static dispatch_once_t onceToken; 18 | dispatch_once(&onceToken, ^{ 19 | SEL selA = @selector(sendAction:to:forEvent:); 20 | SEL selB = @selector(mySendAction:to:forEvent:); 21 | Method methodA = class_getInstanceMethod(self,selA); 22 | Method methodB = class_getInstanceMethod(self, selB); 23 | //将 methodB的实现 添加到系统方法中 也就是说 将 methodA方法指针添加成 方法methodB的 返回值表示是否添加成功 24 | BOOL isAdd = class_addMethod(self, selA, method_getImplementation(methodB), method_getTypeEncoding(methodB)); 25 | //添加成功了 说明 本类中不存在methodB 所以此时必须将方法b的实现指针换成方法A的,否则 b方法将没有实现。 26 | if (isAdd) { 27 | class_replaceMethod(self, selB, method_getImplementation(methodA), method_getTypeEncoding(methodA)); 28 | }else{ 29 | //添加失败了 说明本类中 有methodB的实现,此时只需要将 methodA和methodB的IMP互换一下即可。 30 | method_exchangeImplementations(methodA, methodB); 31 | } 32 | }); 33 | } 34 | - (NSTimeInterval)timeInterval{ 35 | return [objc_getAssociatedObject(self, _cmd) doubleValue]; 36 | } 37 | - (void)setTimeInterval:(NSTimeInterval)timeInterval{ 38 | objc_setAssociatedObject(self, @selector(timeInterval), @(timeInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 39 | 40 | } 41 | //当我们按钮点击事件 sendAction 时 将会执行 mySendAction 42 | - (void)mySendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{ 43 | if (self.isIgnore) { 44 | //不需要被hook 45 | [self mySendAction:action to:target forEvent:event]; 46 | return; 47 | } 48 | if ([NSStringFromClass(self.class) isEqualToString:@"UIButton"]) { 49 | self.timeInterval =self.timeInterval == 0 ?defaultInterval:self.timeInterval; 50 | if (self.isIgnoreEvent){ 51 | return; 52 | }else if (self.timeInterval > 0){ 53 | [self performSelector:@selector(resetState) withObject:nil afterDelay:self.timeInterval]; 54 | } 55 | } 56 | //此处 methodA和methodB方法IMP互换了,实际上执行 sendAction;所以不会死循环 57 | self.isIgnoreEvent = YES; 58 | [self mySendAction:action to:target forEvent:event]; 59 | } 60 | //runtime 动态绑定 属性 61 | - (void)setIsIgnoreEvent:(BOOL)isIgnoreEvent{ 62 | // 注意BOOL类型 需要用OBJC_ASSOCIATION_RETAIN_NONATOMIC 不要用错,否则set方法会赋值出错 63 | objc_setAssociatedObject(self, @selector(isIgnoreEvent), @(isIgnoreEvent), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 64 | } 65 | - (BOOL)isIgnoreEvent{ 66 | //_cmd == @select(isIgnore); 和set方法里一致 67 | return [objc_getAssociatedObject(self, _cmd) boolValue]; 68 | } 69 | - (void)setIsIgnore:(BOOL)isIgnore{ 70 | // 注意BOOL类型 需要用OBJC_ASSOCIATION_RETAIN_NONATOMIC 不要用错,否则set方法会赋值出错 71 | objc_setAssociatedObject(self, @selector(isIgnore), @(isIgnore), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 72 | } 73 | - (BOOL)isIgnore{ 74 | //_cmd == @select(isIgnore); 和set方法里一致 75 | return [objc_getAssociatedObject(self, _cmd) boolValue]; 76 | } 77 | - (void)resetState{ 78 | [self setIsIgnoreEvent:NO]; 79 | } 80 | @end 81 | --------------------------------------------------------------------------------