The introduction of

We should know before we start this article

  • Objc_msgsend Quick message Lookup (part 1) 
  • Objc_msgsend (middle) Slow message search 

When fast message search and message slow search can not find IMP, Apple system is how to deal with the follow-up we come to learn together! What are the main things that method dynamic resolution does?

The preparatory work

  • Objc4-818.2 – the source code

resolveMethod_lockedDynamic method resolution

  • Assign imp = forward_IMP

  • A singleton judgment dynamic control execution process is performed only once according to the behavior method.

Dynamic resolution of object methods

Dynamic resolution of class methods

lookUpImpOrForwardTryCache

cache_getImp

  • Apple is giving a dynamic resolution a chance to save the APP
  • Use this if it’s a classresolveInstanceMethod
  • Use this if it is a metaclassresolveClassMethod

Imp = forward_IMP, const IMP forward_IMP = (imp)_objc_msgForward_impcache;

_objc_msgForward_impcache inquiry

  • __objc_forward_handlerI’m going to focus on this function

__objc_forward_handler

Code Case study

   int main(int argc, const char * argv[]) {
    @autoreleasepool {
        LGTeacher *p = [LGTeacher alloc];
        [t sayHappy];
        [LGTeacher saygood];
    }
    return 0;
}
   
Copy the code

The collapse of information

KCObjcBuild[12626:762145] +[LGTeacher sayHappy]: Unrecognized Selector sent to class 0x100008310 2021-11-28 22:36:39.226012+0800 KCObjcBuild[12626:762145] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[LGTeacher sayHappy]: unrecognized selector sent to class 0x100008310'Copy the code

Dynamic method resolution handling object method not found

Code dynamic resolution handling IMP fix crashes

@implementation LGTeacher -(void)text{ NSLog(@"%s", __func__ ); } +(void)say777{ NSLog(@"%s", __func__ ); } // object method dynamic resolution +(BOOL**)resolveInstanceMethod: SEL SEL {if (SEL == @selector(sayHappy)) {IMP IMP =class_getMethodImplementation(self, @selector(text)); Method m = class_getInstanceMethod(self, @selector(text)); const char * type = method_getTypeEncoding(m); return** class_addMethod(self, sel, imp, type); } return [super resolveInstanceMethod:sel]; } resolveClassMethod:(SEL) SEL {if (SEL == @selector(saygood)) {IMP imp7 = class_getMethodImplementation(objc_getMetaClass("LGTeacher"), @selector(say777)); Method m = class_getInstanceMethod(objc_getMetaClass("LGTeacher"), @selector(say777)); const char type = method_getTypeEncoding(m); return class_addMethod(objc_getMetaClass("LGTeacher"), sel, imp7, type); } return [super resolveClassMethod:sel]; } @endCopy the code

Run print information

2021-11-29 16:30:46.403671+0800 KCObjcBuild[27071:213498] -[LGTeacher text]

2021-11-29 16:30:46.404186+0800 KCObjcBuild[27071:213498] +[LGTeacher say777]
Copy the code
  • Unable to find imp we dynamically add oneimpBut it’s too much trouble.
  • Instance method method lookup processClass -> parent ->NSObject->nil
  • Class method lookup flowMetaclass -> parent -> root metaclass -NsObject->nil

We’re going to find NSobject eventually. We can deal with NSobject uniformly so we can create a category for NSobject

@implementation NSObject (Xu) +(BOOL)resolveInstanceMethod:(SEL)sel{ if (@selector(sayHello) == sel) { NSLog (@ "- into the % @", NSStringFromSelector (sel)); IMP imp = class_getMethodImplementation(self , @selector(sayHello2)); Method meth = class_getInstanceMethod(self , @selector(sayHello2)); const char * type = method_getTypeEncoding(meth); return class_addMethod(self ,sel, imp, type);; }else if (@selector(test) = sel){NSLog(@"-- into %@--",NSStringFromSelector(sel)); IMP imp = class_getMethodImplementation(object_getClass([self class]), @selector(newTest)); Method meth = class_getClassMethod(object_getClass([self class]) , @selector(newTest)); const char * type = method_getTypeEncoding(meth); return class_addMethod(object_getClass([self class]) ,sel, imp, type);; } return NO; } - (void)sayHello2{ NSLog(@"--%s---",__func__); } +(void)newTest{ NSLog(@"--%s---",__func__); } @endCopy the code

Instance methods are class method calls, and the system automatically calls the resolveInstanceMethod method, which is consistent with the above exploration. Dynamic methods determine the advantages

  • You can handle method crashes in a unified manner. You can report method crashes to the server or jump to the home page
  • If you have different modules in your project you can make business distinctions by naming them differently
  • This approach is called faceted programmingAOP

Methods Dynamic resolution flow chart

The problem

  • resolveInstanceMethodWhy is it called twice?
  • How does the unified solution deal with the judgment problem, whether it’s an object method crash or a class method crash, how does it deal with that?
  • Did Apple not deal with it after the dynamic method decision?