在OC中:
API: class_addMethod往一个Class里添加method
API: class_getInstanceMethod或class_getClassMethod可以判断某个SEL是否存在于Class
API: method_exchangeImplementations 交换方法。
 
最近工作上做了一件事,简单点说就是需要把一些特定Class里的方法func,替换成Hook_func,当Hook_func执行完之后,再执行func。于是很简单地想到了往Class添加一个Hook_func,然后再交换func与Hook_func,就能到达目的。
 
但是,在实现后,却出现了死循环,纠其原因,因为部分Class间存在着继承关系,没有正确地将Method添加到正确的Class中导致。
 
当时为了解决这个问题,重新去理清楚了一下Class中 SEL 与 Method的关系。SEL是一个选择器,相当于指向一个Method的指针,将SEL指向不同的Method,它就会有不一样的特性,method_exchangeImplementations也就是交换SEL指向的Method值来实现方法交换的。
 
在调用class_getInstanceMethod时,是会检查superClass的。
 
如下图,当ClassB继承ClassA时, ClassB中没有SEL func,而ClassA中有SEL func。
 
 
 
这时调用class_getInstanceMethod(ClassB, @selector(func)),是能拿到SEL func的Method的,然后再将ClassB中添加SEL Hook_func后,变成下图。
 
对ClassB调用method_exchangeImplementations后,得到下图。
 
这里可以看到,其实ClassA中的SEL:func已经是指向Method:Hook_func。在对ClassB的实例调用SEL:func时,能达到之前预订的效果,即先执行Hook_func后再执行func。
但在这个时候,如果再对ClassA做类似ClassB的处理,将得到下图:
这时SEL:func和SEL:Hook_func都指向了Method:Hook_func,于是便出现了死循环的问题。
 
最终的解决方法从上图已经可以很明显的看出来了,即在对ClassB做处理的时候,添加的SEL:Hook_func不应该添加到ClassB上,而应该添加到ClassA上,如下图,则问题得已解决。
 
执行下面的这个函数,找到正确的Class,然后再往Class里添加方法和交换方法,问题就解决了:
 Class GetSelectorInsClass(Class hclass, SEL sel, Method sel_method) {
Class super_class = [hclass superclass];
if (!super_class) {
return hclass;
}
Method method = class_getInstanceMethod(super_class, sel);
if (method != sel_method) {
return hclass;
}
return GetSelectorInsClass(super_class, sel, sel_method);
}
 

Objective-c runtime方法替换引发的死循环的更多相关文章

  1. Runtime 方法替换 和 动态添加实例方法 结合使用

    前言: 方法替换,可以替换任意外部类的方法,而动态添加方法只能实现在被添加类创建的对象里,但是将方法替换和动态添加方法结合使用,可以实现,对任意外部类动态添加需要的方法,这个方法可以是类方法也可以是实 ...

  2. iOS开发Runtime 方法替换

    通过#import <objc/runtime.h>我们可以找到: /** * Returns a specified instance method for a given class. ...

  3. swift 基础小结02 -- VFL约束、属性的get和set方法、懒加载、方法替换

    一.属性的get和set方法          1.自定义属性的set和get方法          private(set) var _image:UIImage?     //自定义属性get,s ...

  4. id、name、setter方法注入、构造方法注入、工厂方法注入、注解注入、方法注入、方法替换、Web作用域、普通bean引用Web作用域的bean

    spring IoC的id和name id的命名需要满足XML对id的命名规范,必须以字母开始,后面可以是字母.数字.连字符.下画线.句号.冒号等等号,但逗号和空格是非法的.如果用户确实希望用一些特殊 ...

  5. iOS 11 使用方法替换(Method Swizzling),去掉导航栏返回按钮的文字

    方法一:设置BarButtonItem的文本样式为透明颜色,代码如下: [[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegro ...

  6. iOS 为何使用runtime方法交换多次后却能按照交换顺序依次执行代码逻辑?

    题目: 假设我们有一个ViewController, Category A(ViewController), Category B(ViewController), Category C(ViewCo ...

  7. spring 方法注入、方法替换

    spring 提供了很多的注入方式,set注入.构造注入.p命名空间.c命名空间.字段注入等等,这些没啥可说的了. 方法注入 因为开发时我需要spring管理一个实例,但是这个实例并非单例,应该每一次 ...

  8. OBJC运行时方法替换(Method swizzling)

    在上周associated objects一文中,我们开始探索Objective-C运行时的一些黑魔法.本周我们继续前行,来讨论可能是最受争议的运行时技术:method swizzling.   Me ...

  9. Objective C Runtime 开发介绍

    简介 Objective c 语言尽可能的把决定从编译推迟到链接到运行时.只要可能,它就会动态的处理事情.这就意味着它不仅仅需要一个编译器,也需要一个运行时系统来执行变异好的代码.运行时系统就好像是O ...

随机推荐

  1. Android编程中的5种数据存储方式

    Android编程中的5种数据存储方式 作者:牛奶.不加糖 字体:[增加 减小] 类型:转载 时间:2015-12-03我要评论 这篇文章主要介绍了Android编程中的5种数据存储方式,结合实例形式 ...

  2. ComboBox值排序

    ComboBox值排序先是想通过冒泡排序,但是冒泡排序是int类型,又打算通过下标,进行字符串排序,然后想到了一个简单的办法……先存入ArrayList排序Sort清空ComboBox再遍历存入 ...

  3. [DNS]ACL、also-notify、视图服务器及安全设置

    1. ACL :访问控制列表放在named.conf的头部,如果acl的内容太多,可以另创建一个文件,将acl放在该文件中,再在主配置文件named.conf用include 将文件加载进来(记得放在 ...

  4. (简单) POJ 3087 Shuffle'm Up,枚举。

    Description A common pastime for poker players at a poker table is to shuffle stacks of chips. Shuff ...

  5. JS中的事件大全

    一般事件  onClick            鼠标点击事件,多用在某个对象控制的范围内的鼠标点击 onDblClick        鼠标双击事件 onMouseDown        鼠标上的按 ...

  6. 通过Jenkins跑Jmeter接口测试脚本,我想当有接口跑失败时Jenkins发送邮件通知,这个如何弄呢

    通过Jenkins跑Jmeter接口测试脚本,我想当有接口跑失败时Jenkins发送邮件通知,这个如何弄呢

  7. AFNetworking3.0为何弃用了NSURLConnection

    http://blog.csdn.net/qq_34101611/article/details/51698524 上篇博客说到AFNetworking3.0只提供了NSURLSession的支持.其 ...

  8. iOS给model排序

    今天有朋友问我怎么给Model排序,我顺便写了一个例子, 以下是代码,很简洁可以直接用. Person *per = [[Person alloc] init]; per.name = @" ...

  9. POJ 2373 Yogurt factory

    简单DP. 这周所用的实际花费是上一周的花费+S与这周费用的较小值. #include<cstdio> #include<cstring> #include<cmath& ...

  10. leetcode--011 copy list with random pointer

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA3UAAABjCAIAAACzC75sAAAMTElEQVR4nO3cyYHivBYG0D8n0nIojo ...