Objective-C Runtime 运行时之四:Method Swizzling

理解Method Swizzling是学习runtime机制的一个很好的机会。在此不多做整理,仅翻译由Mattt Thompson发表于nshipster的Method Swizzling一文。

Method Swizzling是改变一个selector的实际实现的技术。通过这一技术,我们可以在运行时通过修改类的分发表中selector对应的函数,来修改方法的实现。

例如,我们想跟踪在程序中每一个view controller展示给用户的次数:当然,我们可以在每个view controller的viewDidAppear中添加跟踪代码;但是这太过麻烦,需要在每个view controller中写重复的代码。创建一个子类可能是一种实现方式,但需要同时创建UIViewController, UITableViewController, UINavigationController及其它UIKit中view controller的子类,这同样会产生许多重复的代码。

这种情况下,我们就可以使用Method Swizzling,如在代码所示:

在这里,我们通过method swizzling修改了UIViewController的@selector(viewWillAppear:)对应的函数指针,使其实现指向了我们自定义的xxx_viewWillAppear的实现。这样,当UIViewController及其子类的对象调用viewWillAppear时,都会打印一条日志信息。

上面的例子很好地展示了使用method swizzling来一个类中注入一些我们新的操作。当然,还有许多场景可以使用method swizzling,在此不多举例。在此我们说说使用method swizzling需要注意的一些问题:

Swizzling应该总是在+load中执行

在Objective-C中,运行时会自动调用每个类的两个方法。+load会在类初始加载时调用,+initialize会在第一次调用类的类方法或实例方法之前被调用。这两个方法是可选的,且只有在实现了它们时才会被调用。由于method swizzling会影响到类的全局状态,因此要尽量避免在并发处理中出现竞争的情况。+load能保证在类的初始化过程中被加载,并保证这种改变应用级别的行为的一致性。相比之下,+initialize在其执行时不提供这种保证—事实上,如果在应用中没为给这个类发送消息,则它可能永远不会被调用。

Swizzling应该总是在dispatch_once中执行

与上面相同,因为swizzling会改变全局状态,所以我们需要在运行时采取一些预防措施。原子性就是这样一种措施,它确保代码只被执行一次,不管有多少个线程。GCD的dispatch_once可以确保这种行为,我们应该将其作为method swizzling的最佳实践。

选择器、方法与实现

在Objective-C中,选择器(selector)、方法(method)和实现(implementation)是运行时中一个特殊点,虽然在一般情况下,这些术语更多的是用在消息发送的过程描述中。

以下是Objective-C Runtime Reference中的对这几个术语一些描述:

  1. Selector(typedef struct objc_selector *SEL):用于在运行时中表示一个方法的名称。一个方法选择器是一个C字符串,它是在Objective-C运行时被注册的。选择器由编译器生成,并且在类被加载时由运行时自动做映射操作。
  2. Method(typedef struct objc_method *Method):在类定义中表示方法的类型
  3. Implementation(typedef id (*IMP)(id, SEL, …)):这是一个指针类型,指向方法实现函数的开始位置。这个函数使用为当前CPU架构实现的标准C调用规范。每一个参数是指向对象自身的指针(self),第二个参数是方法选择器。然后是方法的实际参数。

理解这几个术语之间的关系最好的方式是:一个类维护一个运行时可接收的消息分发表;分发表中的每个入口是一个方法(Method),其中key是一个特定名称,即选择器(SEL),其对应一个实现(IMP),即指向底层C函数的指针。

为了swizzle一个方法,我们可以在分发表中将一个方法的现有的选择器映射到不同的实现,而将该选择器对应的原始实现关联到一个新的选择器中。

调用_cmd

我们回过头来看看前面新的方法的实现代码:

咋看上去是会导致无限循环的。但令人惊奇的是,并没有出现这种情况。在swizzling的过程中,方法中的[self xxx_viewWillAppear:animated]已经被重新指定到UIViewController类的-viewWillAppear:中。在这种情况下,不会产生无限循环。不过如果我们调用的是[self viewWillAppear:animated],则会产生无限循环,因为这个方法的实现在运行时已经被重新指定为xxx_viewWillAppear:了。

注意事项

Swizzling通常被称作是一种黑魔法,容易产生不可预知的行为和无法预见的后果。虽然它不是最安全的,但如果遵从以下几点预防措施的话,还是比较安全的:

  1. 总是调用方法的原始实现(除非有更好的理由不这么做):API提供了一个输入与输出约定,但其内部实现是一个黑盒。Swizzle一个方法而不调用原始实现可能会打破私有状态底层操作,从而影响到程序的其它部分。
  2. 避免冲突:给自定义的分类方法加前缀,从而使其与所依赖的代码库不会存在命名冲突。
  3. 明白是怎么回事:简单地拷贝粘贴swizzle代码而不理解它是如何工作的,不仅危险,而且会浪费学习Objective-C运行时的机会。阅读Objective-C Runtime Reference和查看<objc/runtime.h>头文件以了解事件是如何发生的。
  4. 小心操作:无论我们对Foundation, UIKit或其它内建框架执行Swizzle操作抱有多大信心,需要知道在下一版本中许多事可能会不一样。

转载于:https://www.cnblogs.com/yjg2014/p/5857647.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/573176.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机三级数据库2020年试题,2020年计算机三级数据库考试模拟强化试题及答案...

【导语】“数据库技术”科目考核数据库系统基础知识及数据库应用系统项目开发和维护的基本技能&#xff0c;下文是无忧考网为您搜集整理的2020年计算机三级数据库考试模拟强化试题及答案&#xff0c;有需要的考生不妨多多参考一下我们为您分享的内容。1.数据集成是数据仓库建立…

@loadbalanced在哪个包里面_ABB机器人-选项包

ABB机器人业务有RobotWare 系列产品&#xff0c;Robotware-OS:这个是机器人控制器操作系统&#xff0c;RobotWare-OS 为基础机器人编程和运行提 供了所有必要的功能。买机器人会预装RobotWare-OS。RobotWare 选件: 这个是机器人选项包&#xff0c;RobotWare-OS类似于Windows&am…

abctod_123456

...转载于:https://www.cnblogs.com/gottheg/p/5859591.html

计算机复位启动如何操作,详细介绍计算机的启动方式(冷启动、热启动、复位启动)、注销、待机...

一&#xff1a;计算机的启动方式①冷启动&#xff0c;指计算机在没有加电的状态下初始加电&#xff0c;一般原则是&#xff0c;先开外设电源&#xff0c;后开主机电源&#xff0c;因为主机的运行需要非常稳定的电源&#xff0c;为了防止外设启动引起电源波动影响主机运行&#…

1562区别 洛达1552_洛达1562A与洛达1536u与杰里有哪些区别呢?

由于上一篇文章&#xff0c;有很多人问我有什么区别&#xff0c;怎么判断是1562a以及铂金标anc以及芯片之间的差距等等有关问题&#xff0c;今天特意给大家写下这篇文章&#xff0c;废话就不多说了&#xff0c;大家看接下来的文章吧&#xff01;。相信大家应该对AirPodspro已经…

计算机软件 专利挖掘,专利挖掘五步法,你学会了吗?

专利挖掘方法1.专利挖掘五步法专利挖掘有没有一套通用的流程&#xff0c;既可以不遗漏任何技术创新点&#xff0c;又可以对每个技术创新点进行深入的拓展呢&#xff1f;笔者提出的专利挖掘五步法&#xff0c;或许可以解决此问题。专利挖掘五步法&#xff0c;是指专利挖掘团队按…

大数据相关技术说明(一)

1.什么是ETL&#xff1f; ETL&#xff0c;Extraction-Transformation-Loading的缩写&#xff0c;中文名为数据抽取、转换和加载。ETL负责将分布的、异构数据源中的数据如关系数据、平面数据文件等抽取到临时中间层后进行清洗、转换、集成&#xff0c;最后加载到数据仓库或数据集…

catia利用宏批量改名的方法_谁有CATIA批量改名的宏程序啊

-----------------------------------------------------------批量重命名后批量保存程序说明&#xff1a;程序实现在Product下&#xff0c;对第一层结构树内零件批量重命名&#xff0c;并将重命名后的零件以新零件名保存在当前路径下。程序运行前应先手动将不需要重命名的零部…

上海大学计算机组成原理实验13,上海大学计算机组成原理实验报告11.doc

上海大学计算机组成原理实验报告11上海大学计算机组成原理实验报告11上海大学_计算机组成原理实验报告8 2011级上海大学计算机学院 《计算机组成原理二实验》报告8 姓名&#xff1a;学号&#xff1a; 教师&#xff1a;xxx 时间&#xff1a;xxx 地点&#xff1a;xxx机位&#xf…

股票交易日

题目描述&#xff1a; 在股市的交易日中&#xff0c;假设最多可进行两次买卖(即买和卖的次数均小于等于2)&#xff0c;规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行)。给出一天中的股票变化序列&#xff0c;请写一个程序计算一天可以获得的最大收益。请采用实践复杂…

python小老鼠编程_成都python函数学习教程,Python编写课程

1.urllib2/urllib实现urllib2和urllib是Python中的两个内置模块&#xff0c;要实现HTTP功能&#xff0c;实现方式是以urllib2为主&#xff0c;urllib为辅。1.1首先实现一个完整的请求与响应模型urllib2提供一个基础函数urlopen&#xff0c;通过向指定的URL发出请求来获取数据。…

计算机房防火要求,信息机房如何进行防火设计

众所周知&#xff0c;根据机房的使用性质、管理要求及重要数据丢失或网络中断在经济或社会上造成的损失或影响程度&#xff0c;可将电子信息机房分为A、B、C三级。那么&#xff0c;信息机房如何进行防火设计呢&#xff1f;信息机房如何进行防火设计一、选址计算机房建筑规模大、…

js图片前端压缩多图上传(旋转其实已经好了只是手机端有问题要先压缩再旋转)...

var filechooser document.getElementById("choose");// 用于压缩图片的canvasvar canvas document.createElement("canvas");var ctx canvas.getContext(2d);// 瓦片canvasvar tCanvas document.createElement("canvas");var tctx t…

python 案例串接_Python基础系例--字典串操作

字符串字符串是由数字&#xff0c;字母、下划线组成的一串字符创建字符串&#xff0c;可以使用单引号和双引号&#xff1a;var1 Hello World!var2"Hello World!"访问字符串中的值var “Hello World”print(var[0])#运行结果H字符串更新实例&#xff1a;print(var1[0…

计算机串口通信的作用,串口通信的具体用途是什么

串行接口简称串口&#xff0c;也称串行通信接口或串行通讯接口(通常指COM接口)&#xff0c;是采用串行通信方式的扩展接口。串行接口 (Serial Interface) 是指数据一位一位地顺序传送&#xff0c;其特点是通信线路简单&#xff0c;只要一对传输线就可以实现双向通信(可以直接利…

网络连接

网络连接状态&#xff1a; C: S: SYN_SEND             SYN_RECVESTABLISH             ESTABLISH FIN_WAIT1             CLOSE_WAITFIN_WAIT2             LAST_ACK TIME_WAIT      …

拯救者r7000怎么关闭触控板_联想拯救者R7000(2020版)上手体验,有没有AMD Yes?

联想作为一个老品牌&#xff0c;它的产品线有很多系列(电脑、手机、平板、智能家居)&#xff0c;而我们今天来聊一聊电脑系列中的联想拯救者系列电脑。今年的R7000在五月份发布&#xff0c;而我也在六月份入手了一台&#xff0c;被它的外观吸引。硬件方面的参数&#xff1a;小编…

warframe计算机拒绝访问,Win10运行warframe出现蓝屏DRIVER_CORRUPTED_EXPOOL怎么办

warframe是一款科幻题材的第三人称射击网游&#xff0c;一些用户在windows10系统运行warframe过程中经常出现了电脑蓝屏的现象&#xff0c;并且提示“DRIVER_CORRUPTED_EXPOOL”&#xff0c;这是怎么回事&#xff1f;RIVER CORRUPTED EXPOOL错误是由于Windows 10/8/7上的设备驱…

【SpringMVC学习07】SpringMVC中的统一异常处理

我们知道&#xff0c;系统中异常包括&#xff1a;编译时异常和运行时异常RuntimeException&#xff0c;前者通过捕获异常从而获取异常信息&#xff0c;后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。在开发中&#xff0c;不管是dao层、service层还是controller…

vue取通过key取value_彻底理解Vue中的Watcher、Observer、Dep

思考以下代码new Vue({el: #example,data(){return{obj:{a&#xff1a;1}}}, })当我们写下这行代码时,vue将我们在data内定义的obj对象进行依赖追踪.具体做法为执行new Observer(obj)//经过上面的代码&#xff0c;我们的obj对象会变为以下的样子 {obj:{a:1,__ob__:{ //Observer…