消息转发流程

消息转发流程

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,进入慢速转发流程
  • 慢速转发:通过methodSignatureForSelectorforwardInvocation共同实现,如果methodSignatureForSelector返回值是nil,慢速查找流程结束,如果有返回值forwardInvocation不会崩溃。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值