美文网首页
runtime的消息发送和转发机制

runtime的消息发送和转发机制

作者: huicuihui | 来源:发表于2020-09-10 18:26 被阅读0次

    runtime的消息发送和转发机制

    objc_msgSend

    在OC中,所有的消息调用最后都会通过 objc_msgSend 方法进行访问。通过 objc_msgSend 进行消息调用,为了加快执行速度,这个方法在runtime源码中是用汇编实现的。

    调用方法的时候底层会objc_msgSend查找方法的imp

    发送消息的是一个对象。如果要找类对象需要通过对象的isa指针查找到类对象。

    isa是一个isa_t公用体,里面有很多字段。

    方法有方法缓存

    如果缓存没有 则进行方法列表的遍历

    方法缓存存在cache_t中,cache_t存在类对象objc_class结构体中。

    在objc_class结构体中根据偏移计算相应结构体指针。

    cache_t是一个结构体 里面有一个存储方法缓存的bucket_t数组,bucket_t里面有_imp,_sel。

    根据sel和imp在方法缓存中如果没有找到,则来到__objc_msgSend_uncached方法中进行没有方法缓存的查找。

    总结

    objc_msgSend在查找的时候先进行一个缓存的命中,通过地址的与运算,拿到当前的缓存,和当前要查找的sel进行比对,如果比对上就命中了,直接使用。没有比对上则进行__objc_msgSend_uncached。

    __objc_msgSend_uncached

    没有查找到缓存的时候,需要遍历方法列表。lookUpImpOrForward。

    lookUpImpOrForward

    调用 lookUpImpOrForward 方法,返回值是个 IMP 指针,如果查找到了调用函数的 IMP ,则进行方法的访问

    1. 当前类对象的方法列表中遍历方法列表。
    2. 沿着当前继承链当中的superClass,指针的指向,来进行方法遍历查找。
    3. 一直遍历到Root Class(NSObject)

    消息转发机制 动态特性

    如果没有查到对于方法的 IMP 指针,则进行消息转发机制

    _objc_msgForward消息转发做的几件事

    1. 第一层转发:(动态方法解析)

      调用 resolveInstanceMethod:resolveClassMethod:,允许用户在此时为该Class动态添加实现。如果实现了,则调用并返回YES,那么重新开始objc_msgSend流程。这一次对象会响应这个选择器,一般是因为它已经调用过class_addMethod。本质上是在方法列表中建立SEL和新的IMP关系。新的IMP是自己做的。如果仍没实现,继续下面的动作。

    2. 第二层转发:(标准消息转发,obj_msgForward 方法的转发)找一个备用的接收者来处理消息。

      如果第一层转发返回 NO ,则会进行第二层转发,调用forwardingTargetForSelector:,可以把调用转发到另一个对象,这是类级别的转发,调用另一个类的相同的方法。

      注意:这里不要返回self,否则会形成死循环。

    3. 第三层转发:(标准消息转发,obj_msgForward 方法的转发)爱咋咋地,消息拦截了,自己处理。

      如果第二层转发返回 nil ,则会进入这一层处理

      这层会调用 methodSignatureForSelector:尝试获得一个方法签名。如果获取不到则直接调用doesNotRecognizeSelector:抛出异常。如果能获取到,则返回非nil,创建一个NSInvocation并传给forwardInvocation:

      调用forwardInvocation:方法,将上面获取到的方法签名包装成Invocation传入,如何处理就在这里面了,并返回nil。

      这次是完整的消息转发,因为你可以返回方法签名、动态指定调用方法的Target

    4. 如果转发都失败,调用doesNotRecognizeSelector:,crash抛出异常。

    _objc_msgForward在进行消息转发的过程中会涉及以下几个方法:

    1. resolveInstanceMethod:(resolveClassMethod:)
    2. forwardingTargetForSelector:
    3. methodSignatureForSelector:
    4. forwardInvocation:
    5. doesNotRecognizeSelector:

    一旦调用_objc_msgForward将会跳过查找IMP的过程,直接触发消息转发。

    相关文章

      网友评论

          本文标题:runtime的消息发送和转发机制

          本文链接:https://www.haomeiwen.com/subject/soopektx.html