要在Objective-C中创建一个高度可复用的工具类,以防止按钮的暴力点击,并且使用切面编程(AOP)的方式,我们可以考虑使用Aspects这个库来实现方法的拦截。以下是具体的实现步骤:

第一步:引入Aspects库

首先,需要将Aspects集成到项目中。Aspects是一个轻量级的AOP框架,允许你在运行时拦截类的实例方法和类方法。你可以通过CocoaPods来添加此库:

pod 'Aspects'

第二步:创建UIButton的Category

接下来,创建一个UIButton的Category,用于添加防暴力点击的逻辑。

UIButton+PreventSpam.h:

#import <UIKit/UIKit.h>

@interface UIButton (PreventSpam)

// 设置间隔时间,进行防暴力点击设置
- (void)setPreventSpamInterval:(NSTimeInterval)interval;

@end

UIButton+PreventSpam.m:

#import "UIButton+PreventSpam.h"
#import <objc/runtime.h>
#import <Aspects/Aspects.h>

static const char *UIButton_preventSpamIntervalKey = "UIButton_preventSpamIntervalKey";

@implementation UIButton (PreventSpam)

- (void)setPreventSpamInterval:(NSTimeInterval)interval {
    objc_setAssociatedObject(self, UIButton_preventSpamIntervalKey, @(interval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    // 使用Aspects进行方法拦截
    [self aspect_hookSelector:@selector(sendAction:to:forEvent:) withOptions:AspectPositionInstead usingBlock:^(id<AspectInfo> aspectInfo, SEL action, id target, UIEvent *event) {
        UIButton *button = aspectInfo.instance;
        if (button.isIgnoring) {
            return;
        }
        button.isIgnoring = YES;

        // 执行原始的 sendAction:to:forEvent: 方法
        // 这里直接调用原始方法是不合适的,因为这是一个拦截后的block,我们要重新invoke original invocation
        [[aspectInfo originalInvocation] invoke];
        
        // 延迟间隔时间后,重置为可以点击
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            button.isIgnoring = NO;
        });
    } error:NULL];
}

// 判断当前是否应该忽略点击,通过关联对象添加属性
- (void)setIsIgnoring:(BOOL)isIgnoring {
    objc_setAssociatedObject(self, @selector(isIgnoring), @(isIgnoring), OBJC_ASSOCIATION_ASSIGN);
}

- (BOOL)isIgnoring {
    return [objc_getAssociatedObject(self, @selector(isIgnoring)) boolValue];
}

@end

使用

在适当的位置设置按钮的点击间隔:

#import "UIButton+PreventSpam.h"

[myButton setPreventSpamInterval:1.0]; // 点击间隔设置为1秒

注意

  1. 本示例使用了Aspects库进行方法的拦截,这是一种运行时AOP的技巧。这里利用了Objective-C的动态特性。AOP可以帮助增加代码的可维护性和可复用性,但它也会增加代码的复杂性,使用时需要权衡。

  2. 使用关联对象(objc_setAssociatedObjectobjc_getAssociatedObject)来给UIButton动态添加属性,用于存储是否应该忽略点击和间隔时间,这是Objective-C扩展现有类功能的常用技巧。

  3. 在实际项目中,可能需要考虑多种情况和细节,如处理快速切换界面时按钮点击事件的响应等。

07-23 14:38