【iOS】防止双十一多次剁手——用runtime解决重复点击问题

发现问题

双十一将至,项目上遇到了个问题。用户(QA🙄)连续点击去下单支付的时候,微信/支付宝可能会返回“重复订单”的错误信息(废话你点这么多次能不重复么😂),同理点击按钮多次push的情况也会出现。

解决思路

这个问题主要因为button被多次点击,重复的响应了点击事件。

解决方案

通常是如何解决

一般做法是在按钮点击事件里设置这个按钮不可点击,适当的时间之后再设置回来,或者在点击事件最后设置可以点击。下面是在响应事件的方法内禁止点击的代码。

- (IBAction)clickBtn1:(UIbutton *)sender
{
    sender.enabled = NO;
    doSomething
    sender.enabled = YES;
}

如果想做N秒内禁止点重复击操作则需要用方法performSelector:withObject:afterDelay:如果想解决程序里所有重复点击的方法,需要把每个按钮都写一遍,这不扯淡么…

微笑再见.png

漂亮的解决方法

UIbutton继承自UIControl,可以给UIControl添加Category。
MasterDefaultRepeatEventInterval可以定制时间间隔。

#import <UIKit/UIKit.h>

static NSTimeInterval MasterDefaultRepeatEventInterval = 1.5;

@interface UIControl (Interval)

@property (nonatomic, assign) NSTimeInterval M_repeatEventInterval;
@end

这里用了单例的方法来替换。

#import "UIControl+Interval.h"
#import <objc/runtime.h>

@implementation UIControl (Interval)
- (NSTimeInterval)M_repeatEventInterval {
    return [objc_getAssociatedObject(self, _cmd) doubleValue];
}
- (void)setM_repeatEventInterval:(NSTimeInterval)M_repeatEventInterval {
     objc_setAssociatedObject(self, @selector(M_repeatEventInterval), @(M_repeatEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];
        
        SEL originalselector = @selector(sendAction:to:forEvent:);
        SEL swizzledSelector = @selector(M_sendAction:to:forEvent:);
        
        Method originalMethod = class_getInstanceMethod(class, @selector(sendAction:to:forEvent:));
        Method swizzleMethod = class_getInstanceMethod(class, @selector(M_sendAction:to:forEvent:));

        //添加方法 语法:BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) 若添加成功则返回No
        // cls:被添加方法的类  name:被添加方法方法名  imp:被添加方法的实现函数  types:被添加方法的实现函数的返回值类型和参数类型的字符串
        BOOL didAddMethod = class_addMethod(class, originalselector, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
       
        if (didAddMethod) {
            class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        }else{
            method_exchangeImplementations(originalMethod, swizzleMethod);
        }
        
        
    });
}

- (void)M_sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event {
    static BOOL ignoreEvent = NO;
    if (self.M_repeatEventInterval > 0) {
        if (ignoreEvent) {
            return;
        }else{
            ignoreEvent = YES;
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.M_repeatEventInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                ignoreEvent = NO;
            });
            [self M_sendAction:action to:target forEvent:event];
        }
    }else {
        [self M_sendAction:action to:target forEvent:event];
    }
}

就这样!很快,很棒,很优雅。就这样吧😌


嗨呀,开心.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容