接上篇方法查找流程
动态决议
一个方法调用后,经过汇编快速查找,类方法列表查找,循环遍历父类的方法列表查找,这一番查找后都没有找到,这个时候会进行下一步,动态解析方法
// 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;
}
这一步核心代码为 _class_resolveMethod(cls, sel, inst); 查看内部实现
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*/))
{
// 对象方法 决议
_class_resolveInstanceMethod(cls, sel, inst);
}
}
}
首先,判断当前类不是元类,也就对象方法,也就是会执行 _class_resolveInstanceMethod(cls, sel, inst),查看内部实现
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;
}
// 系统给你一次机会 - 你要不要针对 sel 来操作一下下
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));
}
}
}
当我们调用了一个找不到方法,系统让我们可以主动响应
+(BOOL)resolveInstanceMethod:(SEL)sel,我们可以处理下找不到的sel,系统在调用这个方法后,会再次查找下当前sel imp的实现,这个过程中我们如果给他添加一个imp,下一步就是找到了,那么就不会报错
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);
动态决议后,开始进入消息转发流程
快速转发
我们写一个扩展方法,
extern void instrumentObjcMessageSends(BOOL flag);
打印出来系统的调用方法
打开finder,前往 /tmp/msgSend
查看打印的文件resolveInstanceMethod:
已经分析过了,还有两个陌生的函数
forwardingTargetForSelector:
methodSignatureForSelector:
我们进入系统文档搜索下这个函数
文档的解释是,返回一个可以响应该sel的对象,也就是可以吧这个sel的实现转发给一个指定的对象来解决无法找到imp的实现的问题// 快速转发 - 交给其他对象来处理
//- (id)forwardingTargetForSelector:(SEL)aSelector{
// NSLog(@"%s -- %@",__func__,NSStringFromSelector(aSelector));
// if (aSelector == @selector(saySomething)) {
// return [LGTeacher alloc];
// }
// return [super forwardingTargetForSelector:aSelector];
//}
那么还有一个最后的流程,就是慢速转发了(方法签名) 文档搜索
文档解释:返回一个NSMethodSignature对象,该对象包含由给定选择器标识的方法的描述。// 慢速转发
- (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__);
// 事情 - 事务 - 秘书 - 失效
// 系统本质
// SEL aSelector = [anInvocation selector];
//
// if ([[LGTeacher alloc] respondsToSelector:aSelector])
// [anInvocation invokeWithTarget:[LGTeacher alloc]];
// else
// [super forwardInvocation:anInvocation];
}
通过慢速转发后,所有未处理的事物会进入forwardInvocation,我们可以在这里进行事物的处理,比如收集等等
最后附上消息转发的流程图