当前位置: 首页 > 科技观察

IMP指针在Runtime中的作用,方便学习

时间:2023-03-12 09:40:14 科技观察

大家可能看过很多朋友在Runtime相关的文章中介绍IMP指针的概念,那么IMP的实际作用是什么呢?让我们从一个函数开始。MethodSwizzling如果你对Runtime有一定的了解,那么你一定听说过或者用过这个函数:voidmethod_exchangeImplementations(Methodm1,Methodm2)通常称之为methodswizzling,是ObjC的“黑魔法”。这两种方法可以互换。比如有这样一个使用场景:我们的程序中有很多ViewController。我想在每个控制器执行ViewDidLoad后将自己更改为控制台,并对项目进行最小的更改。的名字打印出来,方便我调试或者了解工程结构。很多朋友会这样说,让所有的controller继承一个BaseController不就好了吗?这里我想说明一下这样做的弊端:如果你的项目中有很多Controller,你需要修改项目中每一个不继承BaseController的Controller,随意改变层级结构会导致意外的错误。其实我们的目的是重写ViewDidLoad这个方法,在他的方法里面加几句Log,所以我们需要为UIViewController创建一个category,因为我们知道在Catagory中重写一个方法,会覆盖它的原来的方法实现了,但是这样做之后就没办法调用系统原来的方法了,因为在一个方法中调用自己的方法会死循环。所以我们的解决方案是再写一个方法和viewDidLoad“交换”,这样外部对viewDidLoad的调用就会转移到新创建的方法中。同样,当我们调用新创建的方法时,会调用到系统的viewDidLoad。IMP指针其实我们还有一个更简单的方法可以达到同样的目的,使用IMP指针,IMP是Implementation的缩写,顾名思义就是指向一个方法实现的指针,每个方法都有对应的IMP,所以我们可以直接调用方法的IMP指针,避免方法调用死循环的问题。调用IMP的方法与调用普通的C函数是一样的,例如:idreturnObjc=someIMP(objc,SEL,params...);但是如果你的项目没有其他配置,这样调用编译器是不会通过的,我们先看看它的定义:if!OBJC_OLD_DISPATCH_PROTOTYPEStypedefvoid(*IMP)(void/*id,SEL,...*/);elsetypedefid(*IMP)(id,SEL,...);endif默认你的项目是开启这个配置的。在这种情况下,IMP被定义为一个没有参数和返回值的函数。所以需要在项目中搜索这个选项,将其关闭。麻烦的是每次使用都需要修改工程配置,所以这里介绍另一种方法:重新定义一个与带参数的IMP指针相同的指针类型,在获取IMP类型时强制为这个。这样使用IMP指针后,就不需要再为ViewController写额外的新方法了:还有一个地方需要我们注意。如果像这样直接调用IMP,就会出现经典的EXC_BAD_ACCESS错误。我们定义的IMP指针是一个返回值。其实我们获取到的viewDidLoad方法是没有返回值的,所以我们需要重新定义一个和IMP同类型的函数指针,比如VIMP,并将它的返回值设置为Void,这样如果你修改的方法有一个返回值就用IMP,没有返回值就用VIMP。值得注意的是,如果你重写的方法有返回值,不要忘记在***中做return。总结其实直接调用方法的IMP指针比调用方法本身效率更高,所以如果有合适的时机拿到方法的IMP,可以尝试调用。这只是IMP使用的场景之一,还有很多功能,希望大家多多了解。