Follow the method lookup process in the previous section

Dynamic resolution

After a method call, through the assembly quick search, class method list search, loop through the parent class method list search, this search is not found, this time will carry on the next step, dynamic parsing method

// No implementation found. Try method resolver once. 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; }Copy the code

The core code for this step is _class_resolveMethod(CLS, SEL, INST). View the internal implementation

Void _class_resolveMethod(Class CLS, SEL SEL, id inst) {// 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*/) {// object method resolver _class_resolveInstanceMethod(CLS, sel, inst); }}}Copy the code

First, determine that the current class is not a metaclass, that is, the object method, which executes _class_resolveInstanceMethod(CLS, sel, INST) and looks at the internal implementation

static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst) { if (! lookUpImpOrNil(cls->ISA(), SEL_resolveInstanceMethod, cls, NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) { // Resolver not implemented. return; } BOOL (* MSG)(Class, sel, sel) = (typeof(MSG))objc_msgSend; bool resolved = msg(cls, SEL_resolveInstanceMethod, sel); // 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(cls, sel, inst, NO/*initialize*/, YES/*cache*/, NO/*resolver*/); 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)); }}}Copy the code

When we call a method that cannot be found, the system allows us to actively respond

+(BOOL)resolveInstanceMethod:(SEL) SEL, we can handle SEL that cannot be found. After calling this method, the system will look up the implementation of SEL imp again

IMP sayHIMP = class_getMethodImplementation(self, @selector(sayMaster));

 Method sayHMethod = class_getInstanceMethod(self, @selector(sayMaster));
       
 const char *sayHType = method_getTypeEncoding(sayHMethod);
        
return class_addMethod(self, sel, sayHIMP, sayHType);
Copy the code

After the dynamic resolution, the message forwarding process starts

Fast forward

Let’s write an extension method,

extern void instrumentObjcMessageSends(BOOL flag);
Copy the code

Print out the system calling method

Open finder and go to/TMP /msgSend

resolveInstanceMethod:
Copy the code

I’ve analyzed it, and there are two strange functions

forwardingTargetForSelector:
methodSignatureForSelector:
Copy the code

Let’s go into the system documentation and search for this function

/ / fast forward - to other objects to handle / / - (id) forwardingTargetForSelector aSelector: (SEL) {/ / NSLog (@ % s -. %@",__func__,NSStringFromSelector(aSelector)); // if (aSelector == @selector(saySomething)) { // return [LGTeacher alloc]; // } // return [super forwardingTargetForSelector:aSelector]; / /}Copy the code

Then there is the final process, which is the slow forward (method signature) document search

/ / slow forward - (NSMethodSignature *) methodSignatureForSelector: (SEL) aSelector {NSLog (@ % s -. %@",__func__,NSStringFromSelector(aSelector)); if (aSelector == @selector(saySomething)) { // v @ : return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } return [super methodSignatureForSelector:aSelector]; } // - (void)forwardInvocation:(NSInvocation *)anInvocation{ NSLog(@"%s ",__func__); // Invocation invocation = [anInvocation selector]; // // if ([[LGTeacher alloc] respondsToSelector:aSelector]) // [anInvocation invokeWithTarget:[LGTeacher alloc]]; // else // [super forwardInvocation:anInvocation]; }Copy the code

After the slow forwardInvocation, all unprocessed items go to the forwardInvocation where we can handle things like collection and so on

Finally, the flow chart of message forwarding is attached