// ⚠️通过 isa 找到 class/meta-class ldr x13, [x0] // x13 = isa and x16, x13, #ISA_MASK// x16 = class LGetIsaDone: // ⚠️进入 cache 缓存查找,传的参数为 NORMAL // CacheLookup 宏,用于在缓存中查找 SEL 对应方法实现 CacheLookup NORMAL // calls imp or objc_msgSend_uncached
// Optimistic cache lookup if (cache) { // cache = NO,跳过 imp = cache_getImp(cls, sel); if (imp) return imp; }
// runtimeLock is held during isRealized and isInitialized checking // to prevent races against concurrent realization.
// runtimeLock is held during method search to make // method-lookup + cache-fill atomic with respect to method addition. // Otherwise, a category could be added but ignored indefinitely because // the cache was re-filled with the old value after the cache flush on // behalf of the category.
runtimeLock.read();
if (!cls->isRealized()) { // ⚠️如果 receiverClass(消息接受者类) 还未实现,就进行 realize 操作 // Drop the read-lock and acquire the write-lock. // realizeClass() checks isRealized() again to prevent // a race while the lock is down. runtimeLock.unlockRead(); runtimeLock.write();
realizeClass(cls);
runtimeLock.unlockWrite(); runtimeLock.read(); }
// ⚠️如果 receiverClass 需要初始化且还未初始化,就进行初始化操作 // 这里插入一个 +initialize 方法的知识点 // 调用 _class_initialize(cls),该函数中会递归遍历父类,判断父类是否存在且还未初始化 _class_initialize(cls->superclass) // 调用 callInitialize(cls) ,给 cls 发送一条 initialize 消息((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize) // 所以 +initialize 方法会在类第一次接收到消息时调用 // 调用方式:objc_msgSend() // 调用顺序:先调用父类的 +initialize,再调用子类的 +initialize (先初始化父类,再初始化子类,每个类只会初始化1次) if (initialize && !cls->isInitialized()) { runtimeLock.unlockRead(); _class_initialize (_class_getNonMetaClass(cls, inst)); runtimeLock.read(); // If sel == initialize, _class_initialize will send +initialize and // then the messenger will send +initialize again after this // procedure finishes. Of course, if this is not being called // from the messenger then it won't happen. 2778172 }
// ⚠️逐级查找父类的缓存和方法列表,如果找到 imp 就调用并将该方法缓存到 receiverClass 的 cache 中 { 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; } } }
// ⚠️进入“动态方法解析”阶段 // No implementation found. Try method resolver once. if (resolver && !triedResolver) { runtimeLock.unlockRead(); _class_resolveMethod(cls, sel, inst); runtimeLock.read(); // 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; }
// ⚠️进入“消息转发”阶段 // No implementation found, and method resolver didn't help. // Use forwarding. imp = (IMP)_objc_msgForward_impcache; cache_fill(cls, sel, imp, inst);
/*********************************************************************** * log_and_fill_cache * Log this method call. If the logger permits it, fill the method cache. * cls is the method whose cache should be filled. * implementer is the class that owns the implementation in question. **********************************************************************/ staticvoid log_and_fill_cache(Class cls, IMP imp, SEL sel, id receiver, Class implementer) { #if SUPPORT_MESSAGE_LOGGING if (objcMsgLogEnabled) { bool cacheIt = logMessageSend(implementer->isMetaClass(), cls->nameForLogging(), implementer->nameForLogging(), sel); if (!cacheIt) return; } #endif cache_fill (cls, sel, imp, receiver); }
// ⚠️如果“消息发送”阶段未找到方法的实现,进行一次“动态方法解析” if (resolver && !triedResolver) { runtimeLock.unlockRead(); _class_resolveMethod(cls, sel, inst); // ⚠️核心函数 runtimeLock.read(); // 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; // ⚠️标记triedResolver为YES goto retry; // ⚠️再次进入消息发送,从“去 receiverClass 的 cache 中查找方法”这一步开始 }
// ⚠️进入“消息转发”阶段 ...... }
// objc-class.mm(objc4) void _class_resolveMethod(Class cls, SEL sel, id inst) { // ⚠️判断是 class 对象还是 meta-class 对象 if (! cls->isMetaClass()) { // try [cls resolveInstanceMethod:sel] // ⚠️核心函数 _class_resolveInstanceMethod(cls, sel, inst); } else { // try [nonMetaClass resolveClassMethod:sel] // and [cls resolveInstanceMethod:sel] // ⚠️核心函数 _class_resolveClassMethod(cls, sel, inst); if (!lookUpImpOrNil(cls, sel, inst, NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) { _class_resolveInstanceMethod(cls, sel, inst); } } }
/*********************************************************************** * _class_resolveInstanceMethod * Call +resolveInstanceMethod, looking for a method to be added to class cls. * cls may be a metaclass or a non-meta class. * Does not check if the method already exists. **********************************************************************/ staticvoid _class_resolveInstanceMethod(Class cls, SEL sel, id inst) { // ⚠️查看 receiverClass 的 meta-class 对象的方法列表里面是否有 SEL_resolveInstanceMethod 函数 imp // ⚠️也就是看我们是否实现了 +(BOOL)resolveInstanceMethod:(SEL)sel 方法 // ⚠️这里一定会找到该方法实现,因为 NSObject 中有实现 if (! lookUpImpOrNil(cls->ISA(), SEL_resolveInstanceMethod, cls, NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) { // ⚠️如果没找到,说明程序异常,直接返回 // Resolver not implemented. return; }
如果第一个方法中没有返回方法签名,或者我们没有重写第二个方法,系统就会认为我们彻底不想处理这个消息了,这时候就会调用+/- (void)doesNotRecognizeSelector:(SEL)sel方法并抛出经典的 crash:unrecognized selector sent to instance/class,结束 objc_msgSend 的全部流程。
// 伪代码 int __forwarding__(void *frameStackPointer, int isStret) { id receiver = *(id *)frameStackPointer; SEL sel = *(SEL *)(frameStackPointer + 8); constchar *selName = sel_getName(sel); Class receiverClass = object_getClass(receiver);
// ⚠️⚠️⚠️调用 forwardingTargetForSelector: if (class_respondsToSelector(receiverClass, @selector(forwardingTargetForSelector:))) { id forwardingTarget = [receiver forwardingTargetForSelector:sel]; // ⚠️判断该方法是否返回了一个对象且该对象 != receiver if (forwardingTarget && forwardingTarget != receiver) { if (isStret == 1) { int ret; objc_msgSend_stret(&ret,forwardingTarget, sel, ...); return ret; } //⚠️objc_msgSend(返回值, sel, ...); return objc_msgSend(forwardingTarget, sel, ...); } }