消息转发流程
Posted WeaterMr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了消息转发流程相关的知识,希望对你有一定的参考价值。
消息转发流程
forwardingTargetForSelector 快速转发
- (id)forwardingTargetForSelector:(SEL)aSelector
NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
return [Good new];
解析
- 当对象
goodOne
中没有对应的方法实现,可以通过上面这个方法进行重定向,找一个对象顶替goodOne
去实现对应调用的方法。 - 方法名称要保持一致。
methodSignatureForSelector消息慢速转发
慢速转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
if (aSelector == @selector(name))
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
return [super methodSignatureForSelector:aSelector];
- (void)forwardInvocation:(NSInvocation *)anInvocation
// NSLog(@"%@ - %@",anInvocation.target,NSStringFromSelector(anInvocation.selector));
Good *s = [Good alloc];
if ([self respondsToSelector:anInvocation.selector])
[anInvocation invoke];
else if ([s respondsToSelector:anInvocation.selector])
[anInvocation invokeWithTarget:s];
else
NSLog(@"%s - %@",__func__,NSStringFromSelector(anInvocation.selector));
直接通过 forwardInvocation 将方法重定向到别的对象的方法
- (void)forwardInvocation:(NSInvocation *)anInvocation
Good *s = [Good alloc];
anInvocation.target = s;
anInvocation.selector = @selector(tell1111);
[anInvocation invoke];
解析
methodSignatureForSelector
方法主要是返回对应的方法签名forwardInvocation
主要是设置方法的执行对象与方法的实现。
反汇编研究转发流程
准备
下载Hopper反汇编的工具(打开选择demo)
通过hopper 打开CoreFoundation的可执行文件,去查找__forwarding_prep_0___,CoreFoundation的可执行文件怎么获取
loc_649bb:
stack[-336] = r13;
stack[-320] = r12;
stack[-352] = rsi;
rax = object_getClass(rbx);
r12 = rax;
r13 = class_getName(rax);
if (class_respondsToSelector(r12, @selector(forwardingTargetForSelector:)) == 0x0) goto loc_64a67;
loc_649fc:
rdi = rbx;
rax = [rdi forwardingTargetForSelector:stack[-328]];
if ((rax == 0x0) || (rax == rbx)) goto loc_64a67;
loc_64a19:
loc_64a8a:
rax = class_respondsToSelector(r12, @selector(methodSignatureForSelector:));
r14 = stack[-320];
stack[-336] = r15;
if (rax == 0x0) goto loc_64dd7;
loc_64ab2:
rax = [r14 methodSignatureForSelector:stack[-328]];
rbx = stack[-352];
if (rax == 0x0) goto loc_64e3c;
loc_64ad5:
loc_64ad5:
r12 = rax;
rax = [rax _frameDescriptor];
r13 = rax;
if (((*(int16_t *)(*rax + 0x22) & 0xffff) >> 0x6 & 0x1) != rbx)
rax = sel_getName(stack[-328]);
_CFLog(0x4, @"*** NSForwarding: warning: method signature and compiler disagree on struct-return-edness of '%s'. Signature thinks it does%s return a struct, and compiler thinks it does%s.", rax);
rax = object_getClass(r14);
rax = class_respondsToSelector(rax, @selector(_forwardStackInvocation:));
stack[-344] = r13;
if (rax == 0x0) goto loc_64c19;
loc_64b6c:
loc_64c19:
if (class_respondsToSelector(object_getClass(r14), @selector(forwardInvocation:)) == 0x0) goto loc_64ec2;
loc_64c3b:
rax = [NSInvocation _invocationWithMethodSignature:r12 frame:stack[-336]];
r13 = rax;
[r14 forwardInvocation:rax];
stack[-328] = 0x0;
r14 = 0x0;
goto loc_64c76;
loc_64ec2:
结论
- 快速转发:通过
forwardingTargetForSelector
实现,指定对象接收这个消息,就会走该对象的方法查找流程,如果返回nil,进入慢速转发流程 - 慢速转发:通过
methodSignatureForSelector
和forwardInvocation
共同实现,如果methodSignatureForSelector
返回值是nil
,慢速查找流程结束,如果有返回值forwardInvocation
不会崩溃。
以上是关于消息转发流程的主要内容,如果未能解决你的问题,请参考以下文章