objc_msgSend流程分析:动态方法决议和消息转发

动态方法决议

紧接着上文的快速查找、慢速查找之后,如果还没找到方法,则根据apple提供的建议

  • 进行一次动态方法决议
  • 如果还没找到,则进行消息转发(快速转发、慢速转发)

动态方法决议:Objective C 提供了一种名为动态方法决议的手段,使得我们可以在运行时动态地为一个selector 提供实现。我们只要实现 +resolveInstanceMethod:+resolveClassMethod: 方法,并在其中为指定的selector 提供实现即可(通过调用运行时函数class_addMethod来添加)。

方法解析流程.pic.jpg

static NEVER_INLINE IMP
resolveMethod_locked(id inst, SEL sel, Class cls, int behavior)
{
    runtimeLock.assertLocked();
    ASSERT(cls->isRealized());

    runtimeLock.unlock();
    //对象 -- 类
    if (! cls->isMetaClass()) { //类不是元类,调用对象的解析方法
        // try [cls resolveInstanceMethod:sel]
        resolveInstanceMethod(inst, sel, cls);
    } 
    else {//如果是元类,调用类的解析方法, 类 -- 元类
        // try [nonMetaClass resolveClassMethod:sel]
        // and [cls resolveInstanceMethod:sel]
        resolveClassMethod(inst, sel, cls);
        //为什么要有这行代码? -- 类方法在元类中是对象方法,所以还是需要查询元类中对象方法的动态方法决议
        if (!lookUpImpOrNil(inst, sel, cls)) { //如果没有找到或者为空,在元类的对象方法解析方法中查找
            resolveInstanceMethod(inst, sel, cls);
        }
    }

    // chances are that calling the resolver have populated the cache
    // so attempt using it
    //如果方法解析中将其实现指向其他方法,则继续走方法查找流程
    return lookUpImpOrForward(inst, sel, cls, behavior | LOOKUP_CACHE);
}
  • 判断类是否是元类
    • 如果是类,执行实例方法的动态方法决议resolveInstanceMethod
    • 如果是元类,执行类方法的动态方法决议resolveClassMethod,如果在元类中没有找到或者为空,则在元类的实例方法的动态方法决议resolveInstanceMethod中查找,主要是因为类方法在元类中是实例方法,所以还需要查找元类中实例方法的动态方法决议
  • 如果动态方法决议中,将其实现指向了其他方法,则继续查找指定的imp,即继续慢速查找lookUpImpOrForward

消息转发流程

如果在经历了快速查找、慢速查找、动态方法决议后,仍没有找到方法的实现,就会进行消息转发,消息转发分为:

  • 快速转发:forwardingTargetForSelector
  • 慢速转发:methodSignatureForSelectorforwardInvocation

消息转发的处理主要分为两部分:

【快速转发】当慢速查找,以及动态方法决议均没有找到实现时,进行消息转发,首先是进行快速消息转发,即走到forwardingTargetForSelector方法
如果返回消息接收者,在消息接收者中还是没有找到,则进入另一个方法的查找流程

如果返回nil,则进入慢速消息转发

【慢速转发】执行到methodSignatureForSelector方法
如果返回的方法签名为nil,则直接崩溃报错

如果返回的方法签名不为nil,走到forwardInvocation方法中,对invocation事务进行处理,如果不处理也不会报错

消息转发流程(转自Style_月月).png

objc_msgSend发送消息的流程描述

【快速查找流程】首先,在类的缓存cache中查找指定方法的实现

【慢速查找流程】如果缓存中没有找到,则在类的方法列表中查找,如果还是没找到,则去父类链的缓存和方法列表中查找

【动态方法决议】如果慢速查找还是没有找到时,第一次补救机会就是尝试一次动态方法决议,即重写resolveInstanceMethod/resolveClassMethod方法

【消息转发】如果动态方法决议还是没有找到,则进行消息转发,消息转发中有两次补救机会:快速转发+慢速转发

如果转发之后也没有,则程序直接报错崩溃unrecognized selector sent to instance

你可能感兴趣的:(objc_msgSend流程分析:动态方法决议和消息转发)