objc_msgsend(中)方法动态决议
引入
在学习本文之前我们应该了解
当快速消息查找和消息慢速查找都也找不到imp
时,苹果系统后续是怎么处理的我们一起来学习! 方法动态决议主要做了哪些事情?
准备工作
- objc4-818.2 源码
resolveMethod_locked
动态方法决议
赋值
imp = forward_imp
做了个单例判断动态控制执行流程根据
behavior
方法只执行一次。
对象方法的动态决议
类方法的动态决议
lookUpImpOrForwardTryCache
cache_getImp
- 苹果给与一次动态方法决议的机会来挽救APP
- 如果是类请用
resolveInstanceMethod
- 如果是元类请用
resolveClassMethod
如果都没有处理那么imp = forward_imp ,const IMP forward_imp = (IMP)_objc_msgForward_impcache
;
_objc_msgForward_impcache探究
__objc_forward_handler
主要看这个函数处理
__objc_forward_handler
代码案例分析
int main(int argc, const char * argv[]) {
@autoreleasepool {
LGTeacher *p = [LGTeacher alloc];
[t sayHappy];
[LGTeacher saygood];
}
return 0;
}
崩溃信息
2021-11-28 22:36:39.223567+0800 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'
复制代码
动态方法决议处理对象方法找不到
代码动态决议处理imp修复崩溃
@implementation LGTeacher
-(void)text{
NSLog(@"%s", __func__ );
}
+(void)say777{
NSLog(@"%s", __func__ );
}
// 对象方法动态决议
+(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];
}
//类方法动态决议
+ (BOOL)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];
}
@end
运行打印信息
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]
- 找不到imp我们动态添加一个
imp
,但这样处理太麻烦了。 - 实例方法方法查找流程
类->父类->NSObject->nil
- 类方法查找流程
元类->父类->根元类-NsObject->nil
最终都会找到NSobject.我们可以在NSObject统一处理 所以我们可以给NSObject
创建个分类
@implementation NSObject (Xu)
+(BOOL)resolveInstanceMethod:(SEL)sel{
if (@selector(sayHello) == sel) {
NSLog(@"--进入%@--",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(@"--进入%@--",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__);
}
@end
实例方法是类方法调用,系统都自动调用了resolveInstanceMethod
方法,和上面探究的吻合。 动态方法决议优点
- 可以统一处理方法崩溃的问题,出现方法崩溃可以上报服务器,或者跳转到首页
- 如果项目中是不同的模块你可以根据命名不同,进行业务的区别
- 这种方式叫切面编程熟成
AOP
方法动态决议流程图
问题
resolveInstanceMethod
为什么调用两次?- 统一处理方案怎么处理判断问题,可能是对象方法崩溃也可能是类方法崩溃,怎么处理?
- 动态方法决议后苹果后续就没有处理了吗?
链接:https://juejin.cn/post/7035965819955707935