按钮点击单位时间内不论调用多少次,只执行一次

2020-03-14  本文已影响0人  GemShi
思考

怎么通过留给外部一个简单的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
测试结果
testResult
上一篇 下一篇

猜你喜欢

热点阅读