首页 热点资讯 义务教育 高等教育 出国留学 考研考公
您的当前位置:首页正文

iOS开发:避免按钮短时间内多次响应同一种方法

2024-12-17 来源:花图问答

解决办法

1.在每次点击时先取消之前的操作

- (void)cancelBtnAction:(UIButton *)btn {
    
    [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(toDoSomething:) object: btn];
    [self performSelector:@selector(toDoSomething:)withObject:btn afterDelay: 0.2f];
}

- (void)toDoSomething:(UIButton *)btn {
    
    NSLog(@"在每次点击时先取消之前的操作");
}

2.点击一次后将button的enabled变为NO。在适当的地方把enabled变为YES

3.用Runtime监听点击事件,忽略重复点击,使其规定时间内只响应一次点击事件

  • 为按钮添加多个target方法
//测试本方法之前记得把runtime注释打开
    [testBtn setTitle:@"Runtime防止重复响应事件" forState:UIControlStateNormal];
    [testBtn addTarget:self action:@selector(testBtn:) forControlEvents:UIControlEventTouchUpInside];
    [testBtn addTarget:self action:@selector(testBtnTouchDown:) forControlEvents:UIControlEventTouchDown];
    [testBtn addTarget:self action:@selector(testBtnTouchUpOutside:) forControlEvents:UIControlEventTouchUpOutside];
    testBtn.eventTimeInterval = 2;

解释一下为什么要添加多个target:如果我们不区分target触发的方法,那么一个按钮同时设置多个target,就会出现_wxd_sendAction:to:forEvent:event执行多次,只而触发了一个target,具体触发的是哪个自己试验

  • 在UIButton类目中加入属性
@interface UIButton (Leon)
//  为按钮添加点击间隔 eventTimeInterval秒
@property (nonatomic, assign) NSTimeInterval eventTimeInterval;
@end

@interface UIButton ()

/*
 ***key:方法的名字
 ***value:是否在eventTimeInterval秒内重复点击
 ***问题描述:如果按钮只增加了一个addTarget:action:forControlEvents:网络上的实现方案是没有问题的,如果一个按钮btn增加多个addTarget:action:forControlEvents:方法,则网络上那个就不能实现,这个我做了改版
 ***适用于:同一个按钮,增加了多个addTarget:action:forControlEvents:方法,方法名字必须不同(不然会出现bug)
 ***不完善处:如果能获得是哪种UIControlEvents点击事件,根据那个点击事件来作为ignoreEventDic字典的key才能准确防止同一个按钮,不同的点击事件,来达成防止重复点击的效果
 */
@property (nonatomic, strong) NSMutableDictionary *ignoreEventDic;
@end
  • 然后进行方法的交换
+ (void)load {
    // Method Swizzling
    [self swizzleMethod:@selector(sendAction:to:forEvent:) withMethod:@selector(_wxd_sendAction:to:forEvent:) error:nil];
}

- (void)_wxd_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
    
    if (!self.ignoreEventDic) {
        self.ignoreEventDic = [NSMutableDictionary dictionaryWithCapacity:1];
    }
    self.eventTimeInterval = self.eventTimeInterval == 0 ? defaultInterval : self.eventTimeInterval;
    if ([[self.ignoreEventDic objectForKey:NSStringFromSelector(action)] isEqualToString:@"1"]){
        return;
    } else if (self.eventTimeInterval > 0){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.eventTimeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self.ignoreEventDic setObject:@"0" forKey:NSStringFromSelector(action)];
        });
    }
    
    [self.ignoreEventDic setObject:@"1" forKey:NSStringFromSelector(action)];
    // 这里看上去会陷入递归调用死循环,但在运行期此方法是和sendAction:to:forEvent:互换的,相当于执行sendAction:to:forEvent:方法,所以并不会陷入死循环。
    [self _wxd_sendAction:action to:target forEvent:event];
}

文章是根据前人肩膀上完成,类似的文章很多,自己的总是显得更加完善
有什么不足之处麻烦留言,必改.

显示全文