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_locked
Dynamic 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 class
resolveInstanceMethod
- Use this if it is a metaclass
resolveClassMethod
Imp = forward_IMP, const IMP forward_IMP = (imp)_objc_msgForward_impcache;
_objc_msgForward_impcache inquiry
__objc_forward_handler
I’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 one
imp
But it’s too much trouble. - Instance method method lookup process
Class -> parent ->NSObject->nil
- Class method lookup flow
Metaclass -> 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 programming
AOP
Methods Dynamic resolution flow chart
The problem
resolveInstanceMethod
Why 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?