思考
怎么通过留给外部一个简单的API去实现一个按钮在一定时间间隔内不论点击多少次,只执行一次?
例如,实际开发中,当点击按钮进行网络请求的时候,在接收到响应之前,user可能会暴力点击,如果单位时间内不停的发送网络请求,不仅耗性能,单位时间过后连续的响应也会造成不良的用户体验。
大致步骤
1.首先给按钮一个属性,记录目标时间间隔(创建UIControl分类,通过添加关联对象实现)
2.使用runtime方法交换,捕获系统方法并交换(sendAction:To:ForEvent:)
3.自定义点击事件(添加需要判断时间间隔的逻辑)
具体实现
给UIButton添加RespondOnce分类
@interface UIButton (RespondOnce)
/// 时间间隔 以秒为单位
@property(nonatomic,assign)NSInteger timeInterval;
@end
#import "UIButton+RespondOnce.h"
#import <objc/runtime.h>
static const void *key = &key;
@implementation UIButton (RespondOnce)
+ (void)load
{
//确保只换一次,因为有时候+load可能会调用两次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method method1 = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
Method method2 = class_getInstanceMethod(self, @selector(ss_sendAction:to:forEvent:));
method_exchangeImplementations(method1, method2);
});
}
/// 关联对象 - 自定义setter/getter方法
/// @param timeInterval 参数1 时间间隔
- (void)setTimeInterval:(NSInteger)timeInterval
{
objc_setAssociatedObject(self, key, @(timeInterval), OBJC_ASSOCIATION_ASSIGN);
}
- (NSInteger)timeInterval
{
return [objc_getAssociatedObject(self, key) longValue];
}
/// exchanged method
/// @param action
/// @param target
/// @param event
- (void)ss_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
//定义static变量,延长变量生命周期
static BOOL first = YES;
static NSInteger start = 0;
//获取当前时间戳,以秒为单位
NSInteger now = [[NSString stringWithFormat:@"%f",[[NSDate date] timeIntervalSince1970]] integerValue];
//判断是否在时间间隔内
if (now >= start + self.timeInterval) {
first = YES;
}
//如果是时间间隔周期的首次,记录start时间戳,交换回原点击方法调用,first置为NO
if (first) {
start = now;
[self ss_sendAction:action to:target forEvent:event];
first = NO;
}
}
@end
VC中的实现
- (void)viewDidLoad {
[super viewDidLoad];
UIButton * btn = [[UIButton alloc] initWithFrame:CGRectMake(50, 100, 100, 100)];
btn.timeInterval = 5; //设置时间间隔
[btn setBackgroundColor:[UIColor redColor]];
[btn addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
- (void)click:(UIButton *)btn
{
NSLog(@"%s",__func__);
}
@end
测试结果

网友评论