在上次的objc_msgSend分析的文章中,我们得知,方法的本质就是调用objc_msgSend
函数来发送消息。
接下来我们通过在代码中打断点来跟进一下这个流程。
我们将断点的显示模式改为汇编显示。
然后将代码运行起来。
我们可以很清楚的看到,对象在调用方法时,底层是通过调用
objc_msgSend
函数来发送消息的,我们在objc_msgSend
函数处打上断点,继续跟进去看看。我们可以清楚的看到,objc_msgSend
在缓存没有命中之后调用了_objc_msgSend_uncached
。
_objc_msgSend_uncached
_objc_msgSend_uncached
调用了_class_lookupMethodAndLoadCache3
_class_lookupMethodAndLoadCache3
通过上面的图片,我们可以清楚的看到_class_lookupMethodAndLoadCache3
函数是存在于objc-runtime-new.mm:4845
这个文件中。接下来我们来看看这个函数中都做了些什么。
IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
{
return lookUpImpOrForward(cls, sel, obj,
YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
}
lookUpImpOrForward
- 在类对象的方法列表中查找IMP。
{
Method meth = getMethodNoSuper_nolock(cls, sel);
if (meth) {
log_and_fill_cache(cls, meth->imp, sel, inst, cls);
imp = meth->imp;
goto done;
}
}
- 如果没找到,继续在父类的缓存的方法列表中查找IMP。
{
unsigned attempts = unreasonableClassCount();
for (Class curClass = cls->superclass;
curClass != nil;
curClass = curClass->superclass)
{
// Halt if there is a cycle in the superclass chain.
if (--attempts == 0) {
_objc_fatal("Memory corruption in class list.");
}
// Superclass cache.
imp = cache_getImp(curClass, sel);
if (imp) {
if (imp != (IMP)_objc_msgForward_impcache) {
// Found the method in a superclass. Cache it in this class.
log_and_fill_cache(cls, imp, sel, inst, curClass);
goto done;
}
else {
// Found a forward:: entry in a superclass.
// Stop searching, but don't cache yet; call method
// resolver for this class first.
break;
}
}
// Superclass method list.
Method meth = getMethodNoSuper_nolock(curClass, sel);
if (meth) {
log_and_fill_cache(cls, meth->imp, sel, inst, curClass);
imp = meth->imp;
goto done;
}
}
}
- 如果IMP没有找到,则尝试做一次动态方法解析。
if (resolver && !triedResolver) {
runtimeLock.unlock();
_class_resolveMethod(cls, sel, inst);//这里做一次动态方法解析。
runtimeLock.lock();
// Don't cache the result; we don't hold the lock so it may have
// changed already. Re-do the search from scratch instead.
triedResolver = YES;
goto retry;
}
- 如果没有找到IMP,并且方法解析也没有处理,那么则进入消息转发流程。
// No implementation found, and method resolver didn't help.
// Use forwarding.
imp = (IMP)_objc_msgForward_impcache;
至此,关于方法查找流程的分析就结束了,下一章,我们来分析方法的转发流程。
网友评论