上篇我们讲到了runtime 的动态添加属性和方法,遍历对象的属性列表,今天我们来讲一下runtime里面更好用的东西 - 方法交换。
在OC里面,一个方法的基础对象是objc_method
,他的组成结构如下
一个objc_method 里面包含着 一个SEL(方法名),method_types,和一个method_imp(方法实现的指针),method_imp是一个方法对象里最重要的,它指向该方法实现的地址,所以我们平时看到的方法名,它其实不是一个真正的实现者,可以看作是一个方法唯一的标示。
接下来我们要讲的方法交换,其实就是交换方法实现的指针。我们来看一下runtime里面相关的API:
SEL method_getName(Method m) //获取方法名
IMP method_getImplementation(Method m)//获取方法的指针
int method_getNumberOfArguments(Method m)//获取方法的参数个数
char *method_copyReturnType(Method m)//获取方法返回值的类型
char *method_copyArgumentType(Method m, unsigned int index)//某个参数的类型
IMP method_setImplementation(Method m, IMP imp)//设置方法的指针(替换方法实现)
method_exchangeImplementations(Method m1, Method m2)//交换方法的指针(交换方法实现)
其中,对指针的操作是方法交换的核心内容,用 method_setImplementation 可以进行方法的替换,用method_exchangeImplementations就可以完成交换 其用法如下,
例子1:
方法替换
在图二中,我在UIImage的分类里将imageNamed:的IMP替换成自己写的replaceImage,所以在图3的实现中,我调用imageNamed:的时候,程序就跑到了我我新替换的指针方法实现。
例2:
方法交换
图4我们用method_exchangeImplementations 将两个方法的IMP进行了互换,当我调用imageNamed:的时候,系统根据imageNamed
:里现有的IMP(已被替换成imageWithName:)去找到执行的地址,当我在return 时执行[self imageWithName:name]方法的时候,系统也会根据该方法的IMP去找到相应要执行的地址。因为imageWithName的IMP已经被替换了,所以我执行 return [self imageWithName:name]并不会产生死循环。
说了那么多,方法交换究竟有什么用????
主要用途:批量修改(重定向),数组临界值的问题,UIViewController生命周期的调取
1.批量修改,如上面的例2,该如我需要新增一个换肤系统,就可以用imageWithName
替换原生的imageName,这样在不改变其他代码的情况下,完成资源的切换。
2.数组临界值的问题,突入其来的数据越界让你的措手不及有没有?解决方法如下
例子3:
在NSarray类别中,新建方法securityObjectAtIndex:,并让他与NSarray的 方法objectAtIndex:交换指针
//临界值
*方法的交换我就讲到这里,下篇我们讲解如何避免 unrecognized selector sent to instance (找不到对象/方法)