iOS底层原理:Method Swizzling原理和注意事项(二)

简介: Method Swizzling的含义是方法交换,其核心内容是使用runtime api在运行时将一个方法的实现替换成另一个方法的实现。我们利用它可以替换系统或者我们自定义类的方法实现,进而达到我们的特殊目的,这就是我们常说的iOS黑魔法。



方法交换的坑点和分析



坑点一:交换父类的方法

我们还在刚才的Demo中来演示,现在有一个JQStudent类了,再创建一个JQPerson类,让JQStudent继承JQPerson,在JQPerson类添加一个实例方法personInstanceMethod,在JQStudent类的load方法中将jq_studentInstanceMethod方法和父类中的personInstanceMethod方法进行交换。

实现代码如下图:


image.png

运行结果如下图:


image.png


从上面的结果可以看到:


  • 子类JQStudent对象调用父类JQPerson的方法personInstanceMethod,消息发送会通过方法查找从而找到父类方法并调用。
  • 但是此时父类JQPerson中的方法personInstanceMethod对应的方法实现已经被交换成了子类JQStudentjq_studentInstanceMethod,因此会执行子类的jq_studentInstanceMethod方法实现。
  • 同理,此时子类中调用jq_studentInstanceMethod方法,会执行父类的personInstanceMethod方法实现。

这样看起来好像没有什么问题啊!紧接着,我们再使用父类JQPerson对象调用一下personInstanceMethod方法,如下图:


image.png


啪、啪、啪,报错了!!!我们来分析下什么原因,

  • 首先,父类调换用personInstanceMethod方法会执行子类中的jq_studentInstanceMethod方法实现。


  • 然后又调用了jq_studentInstanceMethod方法,但是,此时的调用者是JQPerson对象,父类JQPerson中并没有jq_studentInstanceMethod方法实现。所以因方法找不到而报错。


出了问题,我们来解决以下,将交换方式换成下面这种:

image.png

image.png

image.png

此时,我们的运行不报错了,而且JQStudent对象调用父类的personInstanceMethod方法,确实走了方法交换后的流程,JQPerson对象也正常的调用了personInstanceMethod方法,互不影响。为什么呢?

原因是:

  1. 在方法交换前,先尝试给本类添加一下oriSEL方法,方法实现为swiMethod
  2. 如果添加成功则返回YES,代表本类中原本没有oriSEL的方法实现;接着,再将父类的方法实现oriMethod替换给本类的swiSEL
  3. 添加失败则返回NO,代表本类中已有oriSEL的方法实现,进行正常的方法交换即可。

坑点二:交换的父类中并没有实现的方法

如果要交换的父类方法并没有实现呢?直接看下运行结果:


image.png

什么情况?我的天,递归了!!!为什么呢?我们断点调试一下,看图解释:


image.png

从上面这些坑中,我们可以得出一些结论:


  • 方法交换要遵循功能单一原则,也就是说本类交换本类中的方法,不能影响父类,否则会影响父类和兄弟姐妹的行为(方法);
  • 即使要交换父类的方法,也要在本类中实现(重写)父类的方法;
  • 本类或父类交换的方法实现不存在,要给本类添加这个方法实现,否则会出现递归调用

基于以上特点,我封装一个更好的方法交换方式,请看以下代码实现:


image.png

运行结果如下:

image.png

相关文章
|
7月前
|
存储 运维 安全
iOS加固原理与常见措施:保护移动应用程序安全的利器
iOS加固原理与常见措施:保护移动应用程序安全的利器
95 0
|
7月前
|
存储 运维 安全
iOS加固原理与常见措施:保护移动应用程序安全的利器
iOS加固原理与常见措施:保护移动应用程序安全的利器
161 0
|
C语言 索引
09-iOS之load和initialize底层调用原理分析
09-iOS之load和initialize底层调用原理分析
99 0
|
5月前
|
算法 iOS开发 C++
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); 的作用和注意事项
默认情况下,C++的输入输出流与C标准库的输入输出函数是同步的,这会造成一定的性能损失。:使用cin.tie(0)和cout.tie(0)可以取消cin与cout之间的绑定,这意味着在进行输入操作时,不需要强行刷新输出缓冲区。:如果你的程序在输入输出中同时使用了C++的输入输出流和C标准库的输入输出函数(如scanf和printf),则不应该使用这段代码。:在使用了这段代码后,应避免使用C标准库的输入输出函数(如printf和scanf),因为这些函数与输入输出流的同步已被关闭。这段代码的主要用途是。
216 1
|
7月前
|
安全 前端开发 数据安全/隐私保护
【教程】 iOS混淆加固原理篇
本文介绍了iOS应用程序混淆加固的缘由,编译过程以及常见的加固类型和逆向工具。详细讨论了字符串混淆、类名、方法名混淆、程序结构混淆加密等加固类型,并介绍了常见的逆向工具和代码虚拟化技术。
|
7月前
|
编解码 Android开发 iOS开发
iOS 上架审核宝典:注意事项与实用工具分享
iOS 上架审核宝典:注意事项与实用工具分享
|
7月前
|
安全 算法 前端开发
【完整版教程】iOS混淆加固原理篇
在iOS开发中,应用程序的安全性和保护显得尤为重要。由于iOS系统的开放性,一些逆向工具可以轻松地对应用程序进行反编译和分析,从而导致应用程序源代码、算法和敏感信息的泄露。为了保护应用程序的安全性,我们需要对应用程序进行混淆加固。本文将介绍iOS混淆加固的原理和常见的加固类型。
|
7月前
|
编解码 Android开发 iOS开发
iOS 上架审核宝典:注意事项与实用工具分享
iOS 上架审核宝典:注意事项与实用工具分享
|
7月前
|
JSON 安全 数据安全/隐私保护
​iOS Class Guard github用法、工作原理和安装详解及使用经验总结
​iOS Class Guard github用法、工作原理和安装详解及使用经验总结
109 0
|
7月前
|
安全 数据安全/隐私保护 iOS开发
【iOS开发】iOS App的加固保护原理:使用ipaguard混淆加固
【iOS开发】iOS App的加固保护原理:使用ipaguard混淆加固
101 0