iOS探究 --- Runtime的初探(消息发送解析)

2020-04-13  本文已影响0人  空空_Jiminy

runtime的三种调用方式
1.runtime api
2.NSObject api
3.OC上层方法 @selector

OC对象

OC对象的本质是一个结构体。
由ivars,imp组成。

方法

方法的本质是发送消息
类似于

void runIMP(id self, SEL _cmd) {
}

我们常见的sel,是一个方法编号。imp是函数实现的指针,通过SEL找到imp,调用函数。
那么问题来,sel是怎么找到imp的?

sel下层通讯

@selector(myFunc)

经过编译将处理为

objc_msgSend(myObjc, sel_registerName("myFunc"));

以上为对象方法,还有
类方法:

objc_msgSend(objc_getClass("MyClass"), sel_registerName("myFunc"))

父类发送消息:(对象方法)

struct objc_super mySuper;
mySuper.receiver = s
mySuper.super_class = class_getSuperclass(s.class)
objc_msgSendSuper(&mySuper, @selector(myFunc))

父类发送消息:(类方法)
struct objc_super myClassSuper;
myClassSuper.receiver = s.class
myClassSuper.super_class = class_getSuperclass(object_getClass());
objc_msgSendSuper(&myClassSuper, sel_registerName("myFunc"));

类方法

对象在类里是一个实例,类在元类里也是一个实例。
所以类方法在元类里,是以对象方法的姿态存在的。

objc_msgSend的两种方式

1.快速查找

在objc_class里
superclass为父类
bits为各种数据
而cache就是一个哈希表。用来存储方法的sel和imp。如果没找到,则走慢速查找。


image.png

2.慢速查找

动态方法解析

当在运行时实例方法并未实现的时候,动态方法解析就可以闪亮登场了。

image.png

上图可以看到,动态解析只会执行一次。

image.png

实例方法执行

_class_resolveInstanceMethod(cls, sel, inst);
+ (BOOL)resolveInstanceMethod:(SEL)sel{
   return [super resolveInstanceMethod:sel];
}

类方法执行

_class_resolveInstanceMethod(cls, sel, inst);
+ (BOOL)resolveClassMethod:(SEL)sel{
    return  [super resolveClassMethod:sel];
}

在实践中,我们会发现resolveInstanceMethod被执行了两次,这是为什么呢?


isa走位流程.png

这时候首先需要搞明白isa的走向。
实例方法 -> 元类 -> 根元类 -> NSObject的实例方法
可知,实例方法调用了一次,NSObject调用了一次。

第一次拯救崩溃

众所周知当调用的方法未实现时,程序会崩溃。
而在方法动态解析时,runtime提供了一次拯救崩溃的机会。

#include <objc/runtime.h>

@interface Person : NSObject

- (void)doSomething;

@end

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    
    if (sel == @selector(doSomething)) {
        //动态方法解析
        SEL otherSel = @selector(otherThing);
        Method otherMethod = class_getInstanceMethod(self, otherSel);
        IMP otherImp = method_getImplementation(otherMethod);
        const char *type = method_getTypeEncoding(otherMethod);
        return class_addMethod(self, otherSel, otherImp, type);
    }
    
    return [super resolveInstanceMethod:sel];
}

类方法同理,为元类动态增加实例方法。

第二次拯救崩溃,方法转发流程

当第一次resolveInstanceMethod执行后,如果消息依然无法进行处理,将会有第二次拯救崩溃的机会,来到消息转发流程。


消息转发流程.png
上一篇下一篇

猜你喜欢

热点阅读