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

iOS开发基础136-防暴力点击的更多相关文章

  1. IOS开发基础知识碎片-导航

    1:IOS开发基础知识--碎片1 a:NSString与NSInteger的互换 b:Objective-c中集合里面不能存放基础类型,比如int string float等,只能把它们转化成对象才可 ...

  2. IOS开发基础环境搭建

    一.目的 本文的目的是windows下IOS开发基础环境搭建做了对应的介绍,大家可根据文档步骤进行mac环境部署: 二.安装虚拟机 下载虚拟机安装文件绿色版,点击如下文件安装 获取安装包:       ...

  3. 【1】windows下IOS开发基础环境搭建

    一.目的 本文的目的是windows下IOS开发基础环境搭建做了对应的介绍,大家可根据文档步骤进行mac环境部署: 二.安装虚拟机 下载虚拟机安装文件绿色版,点击如下文件安装 获取安装包:       ...

  4. iOS开发——总结篇&IOS开发基础知识

    IOS开发基础知识 1:Objective-C语法之动态类型(isKindOfClass, isMemberOfClass,id) 对象在运行时获取其类型的能力称为内省.内省可以有多种方法实现. 判断 ...

  5. iOS开发基础-九宫格坐标(6)

    继续对iOS开发基础-九宫格坐标(5)中的代码进行优化. 优化思路:把字典转模型部分的数据处理操作也拿到模型类中去实现,即将 ViewController 类实现中 apps 方法搬到 WJQAppI ...

  6. iOS开发基础-九宫格坐标(5)

    继续在iOS开发基础-九宫格坐标(4)的基础上进行优化. 一.改进思路 1)iOS开发基础-九宫格坐标(4)中 viewDidLoad 方法中的第21.22行对控件属性的设置能否拿到视图类 WJQAp ...

  7. iOS开发基础-九宫格坐标(4)

    对iOS开发基础-九宫格坐标(3)的代码进行进一步优化. 新建一个 UIView 的子类,并命名为 WJQAppView ,将 appxib.xib 中的 UIView 对象与新建的视图类进行关联. ...

  8. iOS开发基础-九宫格坐标(3)之Xib

    延续iOS开发基础-九宫格坐标(2)的内容,对其进行部分修改. 本部分采用 Xib 文件来创建用于显示图片的 UIView 对象. 一.简单介绍  Xib 和 storyboard 的比较: 1) X ...

  9. iOS开发基础-九宫格坐标(2)之模型

    在iOS开发基础-九宫格(1)中,属性变量 apps 是从plist文件中加载数据的,在 viewDidLoad 方法中的第20行.26行中,直接通过字典的键名来获取相应的信息,使得 ViewCont ...

  10. iOS开发基础-图片切换(4)之懒加载

    延续:iOS开发基础-图片切换(3),对(3)里面的代码用懒加载进行改善. 一.懒加载基本内容 懒加载(延迟加载):即在需要的时候才加载,修改属性的 getter 方法. 注意:懒加载时一定要先判断该 ...

随机推荐

  1. Android 13 - Media框架(32)- ACodec(八)

    关注公众号免费阅读全文,进入音视频开发技术分享群! 拖了好久都没有更新,前面写的东西都有些忘了,回过头来再看之前写的内容,觉得有很多地方写的不好,或者说现在又有了新的理解,想要重新修改但是需要修改的内 ...

  2. Vue3组件通信方式

    Vue3组件通信方式 不管是vue2还是vue3,组件通信方式很重要,不管是项目还是面试都是经常用到的知识点. 比如:vue2组件通信方式 props:可以实现父子组件.子父组件.甚至兄弟组件通信 自 ...

  3. react表单处理 受控组件

    将state与表单项中的value值绑定在一起,有state的值来控制表单元素的值,称为受控组件. 绑定步骤: 在state中添加一个状态,作为表单元素的value值 给表单元素绑定change事件, ...

  4. helm常用命令

    一.helm常用命令 1.查看帮助 helm help 2.创建一个chart包模板 格式: helm create [releasename] 例子: $helm create hello-worl ...

  5. k8s搭建安装 Harbor 私有镜像仓库(本地仓库,内网仓库)

    主要参考 https://www.cnblogs.com/wangzy-Zj/p/14011228.html 额外: 1.如果 harbor.yml中的域名和openssl 生成的不一致,你改了hos ...

  6. EF MYSQL DB FIRST 出现2次数据库名

    环境:使用ADO设计器添加的数据库实体,运行时出现 :Table 'world.world.city' doesn't exist . world 是mysql的演示数据库. MySql.Data.E ...

  7. Sass报错: Using / for division is deprecated

         原因是:当sass版本>= 1.33.0时,会不支持 / 这种语法:  解决方式一:      降低sass版本,将sass版本换成:"sass": "^ ...

  8. 从零开始写 Docker(十八)---容器网络实现(下):为容器插上”网线“

    本文为从零开始写 Docker 系列第十八篇,利用 linux 下的 Veth.Bridge.iptables 等等相关技术,构建容器网络模型,为容器插上"网线". 完整代码见:h ...

  9. 引入feign注入报错 org.springframework.beans.factory.NoSuchBeanDefinitionException解决

    引入feign注入报错 org.springframework.beans.factory.NoSuchBeanDefinitionException解决 [172.16.22.215] out: C ...

  10. docker制作springboot镜像

    以下步骤在具有Docker环境的Linux机器上操作. 把springboot-1.0.0.jar放到/usr/local/springboot目录下,并在该目录下创建Dockerfile文件,内容为 ...