底层12:Runtime-消息机制

2020-09-02  本文已影响0人  张无奈

面试题:讲一下OC的消息机制。

OC中的方法调用其实都是转成了objc_msgSend函数的调用,给receiver(方法调用者)发送了一条消息(selector方法名)。objc_msgSend底层有3大阶段:

消息发送(当前类、父类中直接找)、动态方法解析、消息转发。

消息发送:

1.判断消息接受者是否为nil,为nil就退出;

2.不为nil就通过isa指针找到接受者的类对象,查找里面缓存的方法是否有该消息,

       1)有就调用方法、结束查找。

        2)没有就从rw_t方法列表中查找,

              1>.有就调用方法、结束查找、并将方法缓存到该接收者的缓存列表中;

              2>.没有就通过superClass指针找到父类,再从父类的缓存列表中查找;

                  a. 找到就调用方法、结束查找并将方法缓存到该接收者的缓存列表中;

                  b.没有就从该父类的方法列表中查找;

                        + 有就调用方法、结束查找并将方法缓存到该接收者的缓存列表中,

                        + 没有就继续通过superClass指针继续查找...;

动态方法解析:

最后整个体系都没有就会进入动态方法解析过程,首先判断是否曾经有过动态解析:

没有的话,调用+resolveInstanceMethod或者+resolveClassMethod:方法来动态解析,

并标记为已经动态解析,然后进入消息发送重复上面的过程,最后到曾经有过动态解析直接转入消息转发。

消息转发:

进入消息转发会调用forwardingTargetForSelector:方法。

返回值不为nil,就会调用objc_msgSend(返回值,SEL);

返回值为nil,调用methodSignatureForSelector:方法:

          返回为nil,直接报错方法找不到,调用doesNotRecognizeSelector:方法;

          返回不为nil,调用forwardInvocation方法

面试题:消息转发机制流程?

首先会去实现forwardingTargetForSelector:方法。

1).如果让该方法去执行,即返回值不为nil,就会调用objc_msgSend(返回值,SEL);

2).返回值为nil,调用methodSignatureForSelector:方法。

       a.如果该方法返回为nil,直接报错方法找不到,调用doesNotRecognizeSelector:方法;

       b.返回不为nil,调用forwardInvocation方法,开发者可以在该方法中自定义任何逻辑。



OC中的方法调用,其实都是转换为objc_msgSend函数的调用。

objc_msgSend(对象,@selector(方法))

objc_msgSend如果找不到合适的方法调用,会报错unrecognized selector send to instance

OC的方法调用:消息机制,给方法调用者发送消息。

objc_msgSend的执行流程可以分为3大阶段

消息发送

给方法调用者发送消息,尝试找到方法。找到不会往下进行,否则进行动态方法解析。

动态方法解析

在消息发送阶段没有找到对应的方法,会进入动态方法解析,先判断是否曾经有过动态解析,没有的话,调用+resolveInstanceMethod或者resolveClassMethod:方法来动态解析,并标记为已经动态解析,然后进入消息发送;如果曾经有过动态解析,直接转入消息转发。  

添加实例方法

添加类方法

消息转发:将消息转发给别人

调用forwardingTargetForSelector:方法。返回值不为nil,就会调用objc_msgSend(返回值,SEL);

返回值为nil,调用methodSignatureForSelector:方法。返回为nil,直接报错方法找不到,调用doesNotRecognizeSelector:方法;返回不为nil,调用forwardInvocation方法

能来到forwardInvocation:方法,可以尽情的做你想做的(可以不写,或者打印)。而如上所写相当于把消息转发给MJCat,完全可以在forwardTargetForSelector:方法中实现。

上面是调用实力方法时出现的消息转发过程,调用类方法不存在时新消息转发过程代码如下:

+ (id)forwardingTargetForSelector

@dynamic :提醒编译器不要自动生成setter,getter方法的实现,不要自动生成成员变量。

意味着需要去实现resolveInstanceMethod:方法

@synthesize:提醒编译器生成setter,getter方法,跟@dynamic 相反。(只是后来的Xcode默认就是要生成setter,getter方法,所以也就不需要写了)

上一篇 下一篇

猜你喜欢

热点阅读