当我们查找方法时缓存中没有,父类也没有时,则最后会给 imp = forwarding。
const IMP forward_imp = (IMP)_objc_msgForward_impcache;
这个是什么则是这次探索的目标
IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
{
...
const IMP forward_imp = (IMP)_objc_msgForward_impcache;
...
if (slowpath((curClass = curClass->getSuperclass()) == nil)) {
// No implementation found, and method resolver didn't help.
// Use forwarding.
imp = forward_imp;
break;
}
}
复制代码
- _objc_msgForward_impcache 在源码中的位置,发现调用了
__objc_msgForward
__objc_forward_handler
搜索不到则发现这个方法不是汇编,而搜索_objc_forward_handler
发现这个方法调用了objc_defaultForwardHandler
- 返回值
objc_defaultForwardHandler
上边的错误报错打印
错误方法的处理-消息处理
对象方法动态决议
- 查看宏定义枚举值
- 进入这个方法判断中
- 查看behavior 等于3
- 结果为2大于0 则进入方法
- 进入后改变了behavior的值为1,再次判断的话则为0 不在进入,所以得出结论这个判断只会走一次。是一个单例。
static NEVER_INLINE IMP
resolveMethod_locked(id inst, SEL sel, Class cls, int behavior)
{
runtimeLock.assertLocked();
ASSERT(cls->isRealized());
runtimeLock.unlock();
// 程序员 你是不是傻 没有这个方法 - imp-nil
// 奔溃 - 友善
// 给你一次机会 拯救地球 -> imp
if (! cls->isMetaClass()) {
// try [cls resolveInstanceMethod:sel]
resolveInstanceMethod(inst, sel, cls); //对象方法进入
}
else {
// try [nonMetaClass resolveClassMethod:sel]
// and [cls resolveInstanceMethod:sel]
resolveClassMethod(inst, sel, cls); //类方法进入
if (!lookUpImpOrNilTryCache(inst, sel, cls)) {
resolveInstanceMethod(inst, sel, cls); //由于类在元类中其实也是对象,最终调用父类会进入 NSObject 中,所以要再次调用对象方法的这个处理实现方法中。
}
}
// chances are that calling the resolver have populated the cache
// so attempt using it
return lookUpImpOrForwardTryCache(inst, sel, cls, behavior);
}
复制代码
resolveInstanceMethod(inst, sel, cls);
先进入这个方法处理完成后,调用 lookUpImpOrForwardTryCache
这个方法其实就是调用了_lookUpImpTryCache
这个其实就是消息发送的机制流程,先查找缓存方法,再调用lookUpImpOrForward
方法。
对象方法进入 resolveInstanceMethod
static void resolveInstanceMethod(id inst, SEL sel, Class cls)
{
runtimeLock.assertUnlocked();
ASSERT(cls->isRealized());
SEL resolve_sel = @selector(resolveInstanceMethod:);
if (!lookUpImpOrNilTryCache(cls, resolve_sel, cls->ISA(/*authenticated*/true))) {
// Resolver not implemented.
return;
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(cls, resolve_sel, 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 = lookUpImpOrNilTryCache(inst, sel, cls);
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));
}
}
}
复制代码
- 1.
SEL resolve_sel = @selector(resolveInstanceMethod:);
获取这个方法保存到变量中 - 2.
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(cls, resolve_sel, sel);
判断这个类是否能成功调用 resolveInstanceMethod
方法
resolveInstanceMethod 处理
+ (BOOL)resolveInstanceMethod:(SEL)sel{
// resolveInstanceMethod :LGTeacher-say666 为什么是两次 家庭作业
// 处理 sel -> imp
if (sel == @selector(say666)) {
IMP sayNBImp = class_getMethodImplementation(self, @selector(sayNB));
Method method = class_getInstanceMethod(self, @selector(sayNB));
const char *type = method_getTypeEncoding(method);
return class_addMethod(self, sel, sayNBImp, type);
}
NSLog(@"resolveInstanceMethod :%@-%@",self,NSStringFromSelector(sel));
return [super resolveInstanceMethod:sel];
}
复制代码
resolveClassMethod
static void resolveClassMethod(id inst, SEL sel, Class cls)
{
runtimeLock.assertUnlocked();
ASSERT(cls->isRealized());
ASSERT(cls->isMetaClass());
if (!lookUpImpOrNilTryCache(inst, @selector(resolveClassMethod:), cls)) {
// Resolver not implemented.
return;
}
Class nonmeta;
{
mutex_locker_t lock(runtimeLock);
nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);
// +initialize path should have realized nonmeta already
if (!nonmeta->isRealized()) {
_objc_fatal("nonmeta class %s (%p) unexpectedly not realized",
nonmeta->nameForLogging(), nonmeta);
}
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel);
// Cache the result (good or bad) so the resolver doesn't fire next time.
// +resolveClassMethod adds to self->ISA() a.k.a. cls
IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
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 resolveClassMethod:%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));
}
}
}
复制代码
resolveClassMethod 元类的以对象方法的方法
// 元类的以对象方法的方法
+ (BOOL)resolveClassMethod:(SEL)sel{
NSLog(@"resolveClassMethod :%@-%@",self,NSStringFromSelector(sel));
if (sel == @selector(sayHappy)) {
IMP sayNBImp = class_getMethodImplementation(objc_getMetaClass("LGTeacher"), @selector(sayKC));
Method method = class_getInstanceMethod(objc_getMetaClass("LGTeacher"), @selector(sayKC));
const char *type = method_getTypeEncoding(method);
return class_addMethod(objc_getMetaClass("LGTeacher"), sel, sayNBImp, type);
}
return [super resolveClassMethod:sel];
}
复制代码
创建分类来处理
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (LG)
@end
NS_ASSUME_NONNULL_END
#import "NSObject+LG.h"
#import <objc/message.h>
@implementation NSObject (LG)
- (void)sayNB{
NSLog(@"%@ - %s",self , __func__);
}
+ (void)sayKC{
NSLog(@"%@ - %s",self , __func__);
}
#pragma clang diagnostic push
// 让编译器忽略错误
#pragma clang diagnostic ignored "-Wundeclared-selector"
+ (BOOL)resolveInstanceMethod:(SEL)sel{
// resolveInstanceMethod :LGTeacher-say666 为什么是两次 家庭作业
// 处理 sel -> imp
NSLog(@"resolveInstanceMethod :%@-%@",self,NSStringFromSelector(sel));
if (sel == @selector(say666)) {
IMP sayNBImp = class_getMethodImplementation(self, @selector(sayNB));
Method method = class_getInstanceMethod(self, @selector(sayNB));
const char *type = method_getTypeEncoding(method);
return class_addMethod(self, sel, sayNBImp, type);
}else if (sel == @selector(sayHappy)) {
IMP sayNBImp = class_getMethodImplementation(objc_getMetaClass("LGTeacher"), @selector(sayKC));
Method method = class_getInstanceMethod(objc_getMetaClass("LGTeacher"), @selector(sayKC));
const char *type = method_getTypeEncoding(method);
return class_addMethod(objc_getMetaClass("LGTeacher"), sel, sayNBImp, type);
}
return NO;
}
@end
复制代码
//#pragma clang diagnostic pop
/**
say666 () sel -> imp
1: 苹果给的一次机会
2: 全局 所有方法找不到 我们是不是都能监听
3: lg_model_traffic(项目) -> lg_home_didClickDetail (模块) -> pop home(处理) -> 发送消息didClickDetail (发送后台) -> 监控 改BUG
4: runtime ->
5: aop – oop 漫谈iOS AOP编程之路
6: 对象分工是非常明确 – 冗余代码 -> 提取 -> 公共的类 (强依赖 – 强耦合)
7: 无侵入 – 动态 注入代码 – 切入的方法 切入的类
8: 性能消耗 + 苹果写转发流程就没有意义
9: 消息转发流程 : 快速 + 慢速转发
*/
- 1.由于可能写了一个不存在的方法报错奔溃,对用户的体验不好。系统给了一次机会来处理
- 2.如果方法无法找到就必然会走一次
resolveInstanceMethod
- 3
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END