本文通过分析消息的动态决议,快速转发,慢速转发三个节阶段,完善objc_messend最后流程
-、消息转发:
、动态解析方法resolveinstanceMethod。动态方法解析,class_addMethod()
、如果上面,方法添加没有执行,那么执行消息接受者重定向。【forwardingTargetForSelector】
、如果上面返回nil,就会调用方法签名获取函数的参数和返回值类型,同时调用forwardinvocation通知当前对象。
动态方法决议
对象方法的决议
static void resolveInstanceMethod(id inst, SEL sel, Class cls)
{
SEL resolve_sel = @selector(resolveInstanceMethod:);
//1、检查resolveInstanceMethod的imp是否为空,如果为空,直接返回。nsobject默认实现了,这里主要是检查子类是否实现
if (!lookUpImpOrNilTryCache(cls, resolve_sel, cls->ISA(/*authenticated*/true))) {
// Resolver not implemented.
return;
}
//2、重新定义objc_msgSend
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
//第三个参数`sel`为resolveInstanceMethod的参数,然后发送resolveInstanceMethod消息
bool resolved = msg(cls, resolve_sel, sel);
//3、经过resolveInstanceMethod的处理,可能已经动态添加imp,所以再次获取sel的imp是否存在,如果存在结束转发,否则继续转发
IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
}
类方法的决议的处理流程和对象方法类似。
- 实例代码
+ (BOOL)resolveInstanceMethod:(SEL)sel {
//未实现的方法判断
if (sel == @selector(speak)) {
Method method = class_getInstanceMethod(self, sel);
const char *types = method_getTypeEncoding(method);
IMP imp = class_getMethodImplementation(self, sel);
return class_addMethod(self, sel, imp, types);
}
return [super resolveInstanceMethod:sel];
}
forwardingTargetForSelector
此方法可以直接返回一个对象来接受消息。
实例源码
//交由另外对象处理本条消息
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(speak)) {
//
return [GGXPerson2 alloc];
}
return [super forwardingTargetForSelector:aSelector];
}
另一个类
@implementation GGXPerson2
- (void)speak {
NSLog(@"快速转发forwardingTartgetForSelector");
}
@end
消息慢速转发
methodsignatureForSelector
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(speak)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
SEL aSelector = [anInvocation selector];
if ([[GGXPerson2 alloc] respondsToSelector:aSelector])
[anInvocation invokeWithTarget:[GGXPerson2 alloc]];
else
[super forwardInvocation:anInvocation];
}
问题汇总
- 可以使用动态决议处理崩溃问题,但是需要对方法名过滤
- forwordingtarget转发的对象也未实现,消息转发会在此类进行,进行resovle->forwarding->等方法
- forwarding和methodsingnature,后面会再次执行消息决议是因为,进行了签名,在内部调用栈中,需要判断
class_respondsToSelector
对签名认证。内部调用lookUpImpOrNilTryCache
总的来看:消息转发进入步骤为动态方法决议,快速转发,慢速转发三者按照顺序,成功处理就不进入下个流程
网友评论