事件传递和监控
今天介绍一下UIApplication的函数 - (BOOL)sendAction:to:from:forEvent:
- (BOOL)sendAction:to:from:forEvent: 是 UIApplication 类中的一个方法,主要用于发送事件响应链中的动作(action)。它允许应用程序从一个特定的发送者(sender)向目标(target)发送一个特定的选择器(action),并且将事件(event)与动作一起传递。
- (BOOL)sendAction:(SEL)actionto:(nullable id)targetfrom:(nullable id)senderforEvent:(nullable UIEvent *)event;
参数说明:
action: 要发送的动作(SEL类型),即目标对象应该响应的方法。target: 目标对象,接收action的对象。通常是响应事件的视图控制器或视图对象。sender: 发送者对象,通常是触发事件的控件或视图。它是事件源,可以为空。event: 事件对象,包含关于事件的详细信息。可以为空,通常用于触摸事件。
返回值:
- 返回一个
BOOL类型的值,表示是否成功发送了该动作。YES表示成功,NO表示失败。
使用场景:
此方法通常用于应用程序中触发事件传递的过程中,尤其是在触摸事件和界面控件的交互中。例如,当用户点击按钮时,按钮会触发一个事件,而 sendAction:to:from:forEvent: 方法可以帮助把这个事件传递到目标对象(例如视图控制器)上执行相应的操作。
示例:
// 假设有一个 UIButton,点击时触发相应的动作
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];// 手动发送事件
UIEvent *event = nil; // 事件对象通常由系统管理,手动调用时可以传入nil
[UIApplication.sharedApplication sendAction:@selector(buttonClicked:) to:self from:button forEvent:event];
在这个例子中,sendAction:to:from:forEvent: 方法会将按钮点击的动作传递到目标对象(self,即当前控制器),并调用 buttonClicked: 方法。
注意:
- 该方法通常不是直接调用的,而是系统或控件内部在处理事件时使用。
- 如果目标对象没有实现对应的
action方法,返回值将是NO。 sendAction:to:from:forEvent:可以用于自定义事件传递,但如果目标对象是某些标准 UI 控件(如按钮、滑块等),通常会通过更简单的事件处理方式(例如使用addTarget:action:forControlEvents:)来处理。
其他更有效的使用
监控 iOS 系统的点击事件
在 iOS 中,监控点击事件(如用户点击按钮或其他 UI 元素)是非常常见的需求。有时,我们可能需要追踪每个点击事件的发生,或是对其进行拦截和分析。例如,我们希望记录用户的点击行为,或者实现一些自定义的点击逻辑。
通常,iOS 提供了多种方式来处理点击事件,如 UIButton 的 addTarget:action:forControlEvents:,或者通过重写 touchesBegan、touchesMoved 和 touchesEnded 等方法。但在一些特殊场景下,我们可以通过方法交换(Method Swizzling)来动态替换系统的点击事件处理方法,从而实现对点击事件的监控。
以下介绍如何利用方法交换来监控 iOS 系统的点击事件,具体实现的步骤如下:
1. 理解 iOS 点击事件的流程
在 iOS 中,点击事件通过触摸事件来传递,UI 元素(如按钮、控件等)会接收到触摸事件并触发相应的动作。例如,当用户点击一个按钮时,按钮的 sendAction:to:from:forEvent: 方法会被调用,进而触发目标对象的 action 方法。
我们可以通过方法交换,替换 UIApplication 或 UIControl 的 sendAction:to:from:forEvent: 方法,从而在不修改现有代码的情况下,监听并拦截所有的点击事件。
2. 方法交换简介
方法交换是 Objective-C 中的一种技术,它允许我们动态地交换两个方法的实现。通过方法交换,我们可以在运行时替换一个方法的实现,从而改变其行为。常见的应用场景包括:日志记录、性能分析、事件拦截等。
3. 具体实现:监控点击事件
在这个例子中,我们将通过方法交换来监控 sendAction:to:from:forEvent: 方法的调用,从而捕捉每次点击事件。我们将监控所有 UI 控件的点击事件,并在点击事件发生时输出日志信息。
3.1. 创建 Method Swizzling 方法
首先,我们创建一个 +swizzleSendAction 方法来实现方法交换。我们要交换的目标方法是 sendAction:to:from:forEvent:,目标类是 UIApplication。
#import <UIKit/UIKit.h>
#import <objc/runtime.h>@implementation UIApplication (ClickMonitor)// 定义一个新的方法,作为替换方法
- (BOOL)swizzled_sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event {// 在这里记录点击事件信息NSLog(@"Action: %@, Target: %@, Sender: %@, Event: %@", NSStringFromSelector(action), target, sender, event);// 调用原始方法(返回值需要匹配原方法的返回值类型)return [self swizzled_sendAction:action to:target from:sender forEvent:event];
}// 方法交换
+ (void)load {// 获取原始方法和新方法Method originalMethod = class_getInstanceMethod(self, @selector(sendAction:to:from:forEvent:));Method swizzledMethod = class_getInstanceMethod(self, @selector(swizzled_sendAction:to:from:forEvent:));// 交换方法method_exchangeImplementations(originalMethod, swizzledMethod);
}@end
3.2. 解释代码
- 我们创建了一个类别(Category),
UIApplication (ClickMonitor),为UIApplication类添加了一个新的方法swizzled_sendAction:to:from:forEvent:。 - 在新方法中,我们打印了点击事件的相关信息(例如,
action、target、sender、event)。 - 我们使用
method_exchangeImplementations来交换原始方法sendAction:to:from:forEvent:和我们自定义的swizzled_sendAction:to:from:forEvent:方法。 - 每次调用
sendAction:to:from:forEvent:方法时,实际上会调用我们的替换方法swizzled_sendAction:to:from:forEvent:,从而实现监控点击事件。
3.3. load 方法的作用
在 UIApplication 的类别中实现 +load 方法,这是确保方法交换在应用程序启动时执行的常见方式。+load 方法会在类被加载到内存时自动调用,这样我们就可以在应用启动时就完成方法交换。
3.4. 测试点击事件
我们可以通过简单的 UI 测试,确保方法交换成功工作。假设我们有一个按钮,并希望在按钮点击时触发日志输出:
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:@"Click Me" forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];[self.view addSubview:button];
当用户点击按钮时,swizzled_sendAction:to:from:forEvent: 方法将会被调用,并在控制台输出相关的点击事件信息。
4. 注意事项
- 性能影响:虽然方法交换是强大且灵活的,但它会增加一定的性能开销,因为每次事件都会调用我们自定义的方法。如果有大量的事件需要监控,可能会影响应用的响应速度。
- 调用链:通过方法交换,我们改变了系统方法的行为,因此需要确保原始方法的调用仍然能够顺利执行。在本例中,我们通过在
swizzled_sendAction方法的末尾调用原始方法来保持事件传递链的完整。 - 调试和测试:由于方法交换直接修改了系统行为,可能会影响调试和测试过程。需要在使用方法交换时保持谨慎,确保没有引入难以发现的 bug。
5. 总结
通过方法交换(Method Swizzling),我们能够在运行时修改系统类的方法实现,实现监控 iOS 系统的点击事件。通过替换 sendAction:to:from:forEvent: 方法,我们可以捕捉到所有控件的点击事件,并在其中加入自定义的处理逻辑。虽然方法交换非常强大,但在实际应用中需要小心使用,以避免对性能和系统行为产生不必要的影响。
这种方法为我们提供了在不改变现有代码的情况下,灵活地添加自定义行为的方式,是调试和事件监控中的一种常用技巧。
相关文章:
事件传递和监控
今天介绍一下UIApplication的函数 - (BOOL)sendAction:to:from:forEvent: - (BOOL)sendAction:to:from:forEvent: 是 UIApplication 类中的一个方法,主要用于发送事件响应链中的动作(action)。它允许应用程序从一个特定的发送者(…...
CentOS 7 企业级Redis 7部署指南
CentOS 7 企业级Redis 7部署指南 目录导航 一、环境准备 1.1 依赖管理 二、离线安装 2.1 源码编译安装2.2 目录结构规范 三、生产配置 3.1 主配置文件3.2 配置生成脚本 四、系统集成 4.1 Systemd服务文件4.2 服务管理命令 五、安全加固 5.1 网络安全配置5.2 审计配置 六、性能…...
Python创建Excel的方式——提供4中方式可供参考
目录 专栏导读库的安装代码1——pandas代码2——openpyxl代码3——xlsxwriter代码4——xlwings总结 专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️🌈 博客主页:请点击——>…...
消息中间件深度剖析:以 RabbitMQ 和 Kafka 为核心
在现代分布式系统和微服务架构的构建中,消息中间件作为一个不可或缺的组件,承担着系统间解耦、异步处理、流量削峰、数据传输等重要职能。尤其是在面临大规模并发、高可用性和可扩展性需求时,如何选择合适的消息中间件成为了开发者和架构师们…...
回文数:简单问题中的多种优化思路
回文数:简单问题中的多种优化思路 引言 回文数(Palindrome Number)是一个有趣的问题,在算法竞赛、面试、甚至一些实际应用场景中都会遇到。最直观的方式是将数字转换成字符串,然后反转比较。但仅仅满足“能解”是不够…...
大语言模型简史:从Transformer(2017)到DeepSeek-R1(2025)的进化之路
2025年初,中国推出了具有开创性且高性价比的「大型语言模型」(Large Language Model — LLM)DeepSeek-R1,引发了AI的巨大变革。本文回顾了LLM的发展历程,起点是2017年革命性的Transformer架构,该架构通过「…...
java八股文-spring
目录 1. spring基础 1.1 什么是Spring? 1.2 Spring有哪些优点? 1.3 Spring主要模块 1.4 Spring常用注解 1.5 Spring中Bean的作用域 1.6 Spring自动装配的方式 1.7 SpringBean的生命周期 1.8 多级缓存 1.9 循环依赖? 1 .8.1 原因 1.8…...
机器学习--实现多元线性回归
机器学习—实现多元线性回归 本节顺延机器学习--线性回归中的内容,进一步讨论多元函数的回归问题 y ′ h ( x ) w ⊤ ∙ x b y^{\prime}h(x)w^\top\bullet xb y′h(x)w⊤∙xb 其中, w T ⋅ x 就是 W 1 X 1 w 2 X 2 w 3 X 3 ⋯ w N X N \text{其中,}w^\math…...
vue3响应式丢失解决办法(三)
vue3的响应式的理解,与普通对象的区别(一) vue3 分析总结响应式丢失问题原因(二) 经过前面2篇文章,知道了响应式为什么丢失了,但是还是碰到了丢失情况,并且通过之前的内容还不能解…...
NLP 八股 DAY1:BERT
BERT全称:Pre-training of deep bidirectional transformers for language understanding,即深度双向Transformer。 模型训练时的两个任务是预测句⼦中被掩盖的词以及判断输⼊的两个句⼦是不是上下句。在预训练 好的BERT模型后⾯根据特定任务加上相应的⽹…...
蓝桥与力扣刷题(230 二叉搜索树中第k小的元素)
题目:给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。 示例 1: 输入:root [3,1,4,null,2], k 1 输出:1示例 2ÿ…...
半遮挡检测算法 Detecting Binocular Half-Occlusions
【1. 背景】: 本文分析【Detecting Binocular Half-Occlusions:Empirical Comparisons of Five Approaches】Geoffrey Egnal和Richard P. Wildes于2002年发表在IEEE Transactions on Pattern Analysis and Machine Intelligence上,这是1篇中…...
PHP培训机构教务管理系统小程序
🔑 培训机构教务管理系统——智慧教育,高效管理新典范 🚀 这款教务管理系统,是基于前沿的ThinkPHP框架与Uniapp技术深度融合,匠心打造的培训机构管理神器。它犹如一把开启高效运营与精细管理的金钥匙,专为…...
《LeetCode 763. 划分字母区间 | 高效分割字符串》
内容: 问题描述: 给定一个字符串 S,将字符串分割成若干个子串,使得每个子串中的字符都不重复,并且返回每个子串的长度。 解题思路: 找到每个字符最后一次出现的位置:我们首先遍历一遍字符串&a…...
无人机不等同轴旋翼架构设计应用探究
“结果显示,对于不等组合,用户应将较小的螺旋桨置于上游以提高能效,但若追求最大推力,则两个相等的螺旋桨更为理想。” 在近期的研究《不等同轴旋翼性能特性探究》中,Max Miles和Stephen D. Prior博士深入探讨了不同螺…...
什么是 大语言模型中Kernel优化
什么是 大语言模型中Kernel优化 目录 什么是 大语言模型中Kernel优化Kernel优化操作系统内核优化深度学习计算内核优化手工优化原理举例Flash Attention,Faster TransformerKernel优化 大语言模型存在访存密集操作(如注意力机制、LayerNorm等),这些操作使得GPU计算性能无法…...
DeepSeek与ChatGPT:AI语言模型的全面对决
DeepSeek与ChatGPT:AI语言模型的全面对决 引言:AI 语言模型的时代浪潮一、认识 DeepSeek 与 ChatGPT(一)DeepSeek:国产新星的崛起(二)ChatGPT:AI 界的开拓者 二、DeepSeek 与 ChatGP…...
CTFHub技能树-密码口令wp
目录 引言弱口令默认口令 引言 仅开放如下关卡 弱口令 通常认为容易被别人(他们有可能对你很了解)猜测到或被破解工具破解的口令均为弱口令。 打开环境,是如下界面,尝试一些弱口令密码无果 利用burpsuite抓包,然后爆…...
Deepseek R1模型本地化部署与API实战指南:释放企业级AI生产力
摘要 本文深入解析Deepseek R1开源大模型的本地化部署流程与API集成方案,涵盖从硬件选型、Docker环境搭建到模型微调及RESTful接口封装的完整企业级解决方案。通过电商评论分析和智能客服搭建等案例,展示如何将前沿AI技术转化为实际生产力。教程支持Lin…...
MISP从入门到实战:威胁情报共享平台搭建与使用详解
MISP从入门到实战:威胁情报共享平台搭建与使用详解 目录 MISP核心作用与价值MISP安装与部署 2.1 Docker快速部署2.2 手动安装(Ubuntu) MISP基础使用教程 3.1 创建事件与属性3.2 数据共享与同步3.3 威胁情报分析实战 MISP高级功能 4.1 Galaxy…...
【NLP251】BertTokenizer 的全部 API 及 使用案例
BertTokenizer 是 Hugging Face 的 transformers 库中用于处理 BERT 模型输入的分词器类。它基于 WordPiece 分词算法,能够将文本分割成词汇单元(tokens),并将其转换为 BERT 模型可以理解的格式。BertTokenizer 是 BERT 模型的核心…...
【MySQL常见疑难杂症】常见文件及其所存储的信息
1、MySQL配置文件的读取顺序 (非Win)/etc/my.cnf、/etc/mysql/my.cnf、/usr/local/mysql/etc/my.cnf、~/.my.cnf 可以通过命令查看MySQL读取配置文件的顺序 [roothadoop01 ~]# mysql --help |grep /etc/my.cnf /etc/my.cnf /etc/mysql/my.c…...
InnoDB如何解决幻读?深入解析MySQL的并发控制机制
--- ## 一、什么是幻读(Phantom Read)? **幻读**是数据库事务隔离性中的一个典型问题,具体表现为: 在同一个事务中,多次执行相同的范围查询(Range Query)时,**后一次…...
栈的深度解析:从基础实现到高级算法应用——C++实现与实战指南
一、栈的核心算法与应用场景 栈的先进后出特性使其在以下算法中表现优异: 括号匹配:校验表达式合法性。表达式求值:中缀转后缀,逆波兰表达式求值。深度优先搜索(DFS):模拟递归调用。单调栈&am…...
IDEA集成DeepSeek
引言 随着数据量的爆炸式增长,传统搜索技术已无法满足用户对精准、高效搜索的需求。 DeepSeek作为新一代智能搜索技术,凭借其强大的语义理解与深度学习能力,正在改变搜索领域的游戏规则。 对于 Java 开发者而言,将 DeepSeek 集成…...
Oracle Trace文件突然增长很多的原因分析及解决办法
Oracle Trace文件突然增长很多可能是由多种原因引起的,例如SQL语句的长时间跟踪、错误的跟踪设置、大量的错误和警告信息等。 一、以下是一些解决Trace文件增长过快的方法: 1.清理旧的Trace文件 可以通过以下命令删除超过一定天数的Trace文件,例如删除3天前的Trace文件: …...
leetcode:627. 变更性别(SQL解法)
难度:简单 SQL Schema > Pandas Schema > Salary 表: ----------------------- | Column Name | Type | ----------------------- | id | int | | name | varchar | | sex | ENUM | | salary | int …...
SQLMesh系列教程-3:SQLMesh模型属性详解
SQLMesh 的 MODEL 提供了丰富的属性,用于定义模型的行为、存储、调度、依赖关系等。通过合理配置这些属性,可以构建高效、可维护的数据管道。在 SQLMesh 中,MODEL 是定义数据模型的核心结构,初学SQLMesh,定义模型看到属…...
Java 中的 HashSet 和 HashMap 有什么区别?
一、核心概念与用途 特性HashSetHashMap接口实现实现 Set 接口(存储唯一元素)实现 Map 接口(存储键值对)数据存储存储单个对象(元素唯一)存储键值对(键唯一,值可重复)典…...
Kubernetes-master 组件
以下是Kubernetes Master Machine的组件。 etcd 它存储集群中每个节点可以使用的配置信息。它是一个高可用性键值存储,可以在多个节点之间分布。只有Kubernetes API服务器可以访问它,因为它可能具有一些敏感信息。这是一个分布式键值存储,所…...
