IOS Object-C 中Runtime详解及实例代码

2020-01-18 21:31:31王冬梅

方法调用的过程

调用方法分为调用实例方法和调用类方法,在结构体我们可以看到第一个就是一个 isa 指针,会指向类对象或者元类,什么叫元类呢?

每个实例对象有个isa的指针,他指向对象的类,而类里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass)。根元类的isa指针指向本身,这样形成了一个封闭的内循环。

OC中Runtime,IOS,Object-C,中Runtime详解

通过isa,就可以不断往上方去回溯自己的父类等,而方法的调用也利用了这个过程:

    首先,当然在对象自己缓存的方法列表中去找要调用的方法,找到了就直接执行其实现。 缓存里没找到,就去上面说的它的方法列表里找,找到了就执行其实现。 还没找到,说明这个类自己没有了,就会通过isa去向其父类里执行1、2。 如果找到了根类还没找到,那么就是没有了,会转向一个拦截调用的方法,我们可以自己在拦截调用方法里面做一些处理。 如果没有在拦截调用里做处理,那么就会报错崩溃。

以上就是方法调用的过程。我们可以看到的是,所谓重写父类方法,并不是抹除了父类方法,父类的方法还是存在的,只是我们在子类里面找到了就不会再去父类里找了,是这个层面的“覆盖”。而我们熟悉的 super 调用父类的方法实现,就是告知要去调用父类实现的标识。

拦截调用与动态添加

上面说到了拦截调用,就是在所有地方都找不到方法的实现的话,会出发拦截调用,可以自己去做一些处理避免程序崩溃。那在什么地方做处理呢?NSObject有四个方法可以用来做处理:


// 调用不存在的类方法时触发,默认返回NO,可以加上自己的处理后返回YES
+ (BOOL)resolveClassMethod:(SEL)sel;

// 调用不存在的实例方法时触发,默认返回NO,可以加上自己的处理后返回YES
+ (BOOL)resolveInstanceMethod:(SEL)sel;

// 将调用的不存在的方法重定向到一个其他声明了这个方法的类里去,返回那个类的target
- (id)forwardingTargetForSelector:(SEL)aSelector;

// 将调用的不存在的方法打包成 NSInvocation 给你,自己处理后调用 invokeWithTarget: 方法让某个类来触发
- (void)forwardInvocation:(NSInvocation *)anInvocation;

假设我们成功拦截下来了,那我们可以做什么处理呢?这个其实就是根据具体情况看你要怎么处理了。但这里有一个久闻其名的东西就可以派上用场了:动态添加方法。