动态方法决议
紧接着上文的快速查找、慢速查找之后,如果还没找到方法,则根据apple提供的建议
- 进行一次
动态方法决议
- 如果还没找到,则进行消息转发
(快速转发、慢速转发)
动态方法决议:Objective C 提供了一种名为动态方法决议的手段,使得我们可以在运行时动态地为一个selector
提供实现。我们只要实现 +resolveInstanceMethod:
或 +resolveClassMethod:
方法,并在其中为指定的selector
提供实现即可(通过调用运行时函数class_addMethod
来添加)。

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
- 慢速转发:
methodSignatureForSelector
、forwardInvocation
消息转发的处理主要分为两部分:
【快速转发】当慢速查找,以及动态方法决议均没有找到实现时,进行消息转发,首先是进行快速消息转发,即走到forwardingTargetForSelector
方法
如果返回消息接收者,在消息接收者中还是没有找到,则进入另一个方法的查找流程
如果返回nil,则进入慢速消息转发
【慢速转发】执行到methodSignatureForSelector
方法
如果返回的方法签名为nil,则直接崩溃报错
如果返回的方法签名不为nil,走到forwardInvocation
方法中,对invocation
事务进行处理,如果不处理也不会报错

objc_msgSend发送消息的流程描述
【快速查找流程】首先,在类的缓存cache
中查找指定方法的实现
【慢速查找流程】如果缓存中没有找到,则在类的方法列表
中查找,如果还是没找到,则去父类链的缓存和方法列表
中查找
【动态方法决议】如果慢速查找还是没有找到时,第一次补救机会就是尝试一次动态方法决议,即重写resolveInstanceMethod/resolveClassMethod
方法
【消息转发】如果动态方法决议还是没有找到,则进行消息转发,消息转发中有两次补救机会:快速转发+慢速转发
如果转发之后也没有,则程序直接报错崩溃unrecognized selector sent to instance
网友评论