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