这里主要用到的Runtime在Button的分类中添加属性以及运行时中方法替换.
分类.h文件
#import@interface UIButton (BtnRepetitionClicked)
@property (nonatomic, assign)NSTimeInterval timeInterval;
@end
分类.m文件
#import "UIButton+BtnRepetitionClicked.h"
#import <objc/runtime.h>
static const char completeTimeInterval;
static const char completeEventTime;
@interface UIButton ()
@property (nonatomic ,assign) NSTimeInterval eventTime;
@end
@implementation UIButton (BtnRepetitionClicked)
-(NSTimeInterval)timeInterval { //分类中不能直接使用属性,可以通过关联set,get方法解决这一问题
return [objc_getAssociatedObject(self, &completeTimeInterval) doubleValue];
}
-(void)setTimeInterval:(NSTimeInterval)timeInterval {
//关联的必须是对象,所以timeInterval需要转成对象
objc_setAssociatedObject(self, &completeTimeInterval, @(timeInterval), OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSTimeInterval)eventTime {
return [objc_getAssociatedObject(self, &completeEventTime) doubleValue];
}
-(void)setEventTime:(NSTimeInterval)eventTime {
objc_setAssociatedObject(self, &completeEventTime, @(eventTime), OBJC_ASSOCIATION_COPY_NONATOMIC);
}
+(void)load { //很有诱惑力的方法
//获取着两个方法
SEL sysSEL = @selector(sendAction:to:forEvent:);//获取自带的方法
SEL mySEL = @selector(my_sendAction:to:forEvent:); //获取自己的方法
//方法的交换也是Runtime的黑盒子,具体实现网上很多的
[self swizzleMethod:sysSEL withMethod:mySEL];
}
- (void)my_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{
if (NSDate.date.timeIntervalSince1970 - self.eventTime < self.timeInterval) {
return;
}
if (self.timeInterval > 0) {
self.eventTime = NSDate.date.timeIntervalSince1970;
}
}
[self my_sendAction:action to:target forEvent:event]; //这个方法小白自己的理解是这样的:调用自己的方法,不会循环调用,很神奇.我感觉应该是调用了自带的被交换的方法.其实应该是调用自带的,要不然我们改的可是自带的方法,谁知道底层是怎么实现的.(有理解不一样的,请留言,非常感谢!!!!!)
}
注:这里可以给个默认的间隔(),但是感觉不好,用户体验上面有点牵强.个人不提倡
- (void)my_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{
if (NSDate.date.timeIntervalSince1970 - self.eventTime < self.timeInterval + 2) {
return;
}
//if (self.timeInterval > 0) {
self.eventTime = NSDate.date.timeIntervalSince1970;
//}
}
网友评论