要在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秒
注意
本示例使用了
Aspects
库进行方法的拦截,这是一种运行时AOP的技巧。这里利用了Objective-C的动态特性。AOP可以帮助增加代码的可维护性和可复用性,但它也会增加代码的复杂性,使用时需要权衡。使用关联对象(
objc_setAssociatedObject
和objc_getAssociatedObject
)来给UIButton动态添加属性,用于存储是否应该忽略点击和间隔时间,这是Objective-C扩展现有类功能的常用技巧。在实际项目中,可能需要考虑多种情况和细节,如处理快速切换界面时按钮点击事件的响应等。