IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior) { const IMP forward_imp = (IMP)_objc_msgForward_impcache; IMP imp = nil; Class curClass;
runtimeLock.assertUnlocked();
if (fastpath(behavior & LOOKUP_CACHE)) { // cache_getImp 为汇编实现,内部实际上就是执行前面快速查找流程 imp = cache_getImp(cls, sel); if (imp) goto done_nolock; } // 加锁 runtimeLock.lock();
// 查询是否为已知类 checkIsKnownClass(cls);
// 类没有实现,尝试实现 if (slowpath(!cls->isRealized())) { cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock); // runtimeLock may have been dropped but is now locked again }
auto const methods = cls->data()->methods(); for (auto mlists = methods.beginLists(), end = methods.endLists(); mlists != end; ++mlists) { // <rdar://problem/46904873> getMethodNoSuper_nolock is the hottest // caller of search_method_list, inlining it turns // getMethodNoSuper_nolock into a frame-less function and eliminates // any store from this codepath. method_t *m = search_method_list_inline(*mlists, sel); if (m) return m; }
// chances are that calling the resolver have populated the cache // so attempt using it return lookUpImpOrForward(inst, sel, cls, behavior | LOOKUP_CACHE); }
其中调用的 lookUpImpOrNil 函数源码如下:
1 2 3 4 5
staticinline IMP lookUpImpOrNil(id obj, SEL sel, Class cls, int behavior = 0) { return lookUpImpOrForward(obj, sel, cls, behavior | LOOKUP_CACHE | LOOKUP_NIL); }
staticvoid resolveInstanceMethod(id inst, SEL sel, Class cls) { runtimeLock.assertUnlocked(); ASSERT(cls->isRealized()); SEL resolve_sel = @selector(resolveInstanceMethod:);
if (!lookUpImpOrNil(cls, resolve_sel, cls->ISA())) { // Resolver not implemented. // 如果你没有实现类方法 +(BOOL)resolveInstanceMethod:(SEL)sel // NSObject 已经实现了,所以一般不会走这里 return; }
// 检测是否有 sel 对应的 IMP。如在 +(BOOL)resolveInstanceMethod:(SEL)sel 中动态添加了 sel 对应方法,此时再次去查找这个 IMP 就能找到,并且在这一步就会将其保存到缓存中,下次调用从缓存中就可以找到了。 // Cache the result (good or bad) so the resolver doesn't fire next time. // +resolveInstanceMethod adds to self a.k.a. cls IMP imp = lookUpImpOrNil(inst, sel, cls);
if (resolved && PrintResolving) { if (imp) { _objc_inform("RESOLVE: method %c[%s %s] " "dynamically resolved to %p", cls->isMetaClass() ? '+' : '-', cls->nameForLogging(), sel_getName(sel), imp); } else { // Method resolver didn't add anything? _objc_inform("RESOLVE: +[%s resolveInstanceMethod:%s] returned YES" ", but no new implementation of %c[%s %s] was found", cls->nameForLogging(), sel_getName(sel), cls->isMetaClass() ? '+' : '-', cls->nameForLogging(), sel_getName(sel)); } } }
static void resolveClassMethod(id inst, SEL sel, Class cls) { runtimeLock.assertUnlocked(); ASSERT(cls->isRealized()); ASSERT(cls->isMetaClass());
if (!lookUpImpOrNil(inst, @selector(resolveClassMethod:), cls)) { // Resolver not implemented. return; }
Class nonmeta; { mutex_locker_t lock(runtimeLock); nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst); // +initialize path should have realized nonmeta already if (!nonmeta->isRealized()) { _objc_fatal("nonmeta class %s (%p) unexpectedly not realized", nonmeta->nameForLogging(), nonmeta); } } BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend; bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel);
// Cache the result (good or bad) so the resolver doesn't fire next time. // +resolveClassMethod adds to self->ISA() a.k.a. cls IMP imp = lookUpImpOrNil(inst, sel, cls);
if (resolved && PrintResolving) { if (imp) { _objc_inform("RESOLVE: method %c[%s %s] " "dynamically resolved to %p", cls->isMetaClass() ? '+' : '-', cls->nameForLogging(), sel_getName(sel), imp); } else { // Method resolver didn't add anything? _objc_inform("RESOLVE: +[%s resolveClassMethod:%s] returned YES" ", but no new implementation of %c[%s %s] was found", cls->nameForLogging(), sel_getName(sel), cls->isMetaClass() ? '+' : '-', cls->nameForLogging(), sel_getName(sel)); } } }
动态方法解析总结:
如果不是元类(说明当前是对象方法),进行对象方法的动态方法解析。
如果实现了 +(BOOL)resolveInstanceMethod:(SEL)sel 方法并且在方法中动态添加了 sel 对应方法,后面调用 lookUpImpOrNil 函数就能找到对应 imp,并且会将方法保存到缓存里。下次就能直接从缓存中找到 sel 并调用了。
如果是元类(说明当前是类方法),先进行类方法的动态方法解析,如果没在 + (BOOL)resolveClassMethod:(SEL)sel 中动态添加 sel 对应方法,则执行一次对象方法解析。
if (class_respondsToSelector(receiverClass, @selector(methodSignatureForSelector:))) { NSMethodSignature *methodSignature = [receiver methodSignatureForSelector:sel]; if (methodSignature) { BOOL signatureIsStret = [methodSignature _frameDescriptor]->returnArgInfo.flags.isStruct; if (signatureIsStret != isStret) { CFLog(kCFLogLevelWarning , @"*** NSForwarding: warning: method signature and compiler disagree on struct-return-edness of '%s'. Signature thinks it does%s return a struct, and compiler thinks it does%s.", sel_getName(sel), signatureIsStret ? "" : not, isStret ? "" : not); } if (class_respondsToSelector(receiverClass, @selector(forwardInvocation:))) { NSInvocation *invocation = [NSInvocation _invocationWithMethodSignature:methodSignature frame:frameStackPointer]; [receiver forwardInvocation:invocation];
void *returnValue = NULL; [invocation getReturnValue:&value]; return returnValue; } else { CFLog(kCFLogLevelWarning , @"*** NSForwarding: warning: object %p of class '%s' does not implement forwardInvocation: -- dropping message", receiver, className); return0; } } }
constchar *selName = sel_getName(sel); SEL *registeredSel = sel_getUid(selName);
if (sel != registeredSel) { CFLog(kCFLogLevelWarning , @"*** NSForwarding: warning: selector (%p) for message '%s' does not match selector known to Objective C runtime (%p)-- abort", sel, selName, registeredSel); } elseif (class_respondsToSelector(receiverClass, @selector(doesNotRecognizeSelector:))) { [receiver doesNotRecognizeSelector:sel]; } else { CFLog(kCFLogLevelWarning , @"*** NSForwarding: warning: object %p of class '%s' does not implement doesNotRecognizeSelector: -- abort", receiver, className); }