iOS底层原理13:消息转发流程

2021-07-19  本文已影响0人  黑白森林无间道

iOS底层原理12:动态方法决议中探究了动态方法决议。在动态决议之后,通过日志辅助功能认识到forwardingTargetForSelectormethodSignatureForSelector方法,也就是消息发送的最后一个流程消息转发

准备工作

消息转发

消息发送在经过动态方法决议后,仍然没有查找到正真的方法实现,此时进入消息转发流程。转发流程分两步快速转发慢速转发

快速转发流程

通过日志辅助发现,在崩溃之前会执行forwardingTargetForSelector方法,即消息快速流程

forwardingTargetForSelector方法探究

打开Xcode,通过快捷键command + shift + 0打开开发者文档,然后搜索forwardingTargetForSelector,结果如下图

image

代码验证

image
- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
    
    if (aSelector == @selector(sayHello)) {
        return [[HTCommon alloc] init];
    } else if (aSelector == @selector(sayBye)) {
        return [HTCommon class];
    }
    return [NSObject alloc];
}
image

【问题】如何通过消息转发快速流程,来处理类方法呢?这里猜测需要通过+ (id)forwardingTargetForSelector:(SEL)aSelector {} 来处理类方法

- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
    
    if (aSelector == @selector(sayHello)) {
        return [[HTCommon alloc] init];
    }
    return [NSObject alloc];
}

+ (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
    
    if (aSelector == @selector(sayBye)) {
        return [HTCommon class];
    }
    return [NSObject class];
}
image

慢速转发流程

如果通过快速转发流程forwardingTargetForSelector还是找不到方法实现,接下来苹果还给了我们一次机会,即慢速转发流程

image

代码验证

#pragma mark- 处理对象方法
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    
    NSLog(@"%s -- %@", __func__, NSStringFromSelector(aSelector));
    if (aSelector == @selector(sayHello)) {
        return [NSMethodSignature signatureWithObjCTypes:"v:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    
    NSLog(@"%s -- %@", __func__, NSStringFromSelector(anInvocation.selector));
    
    if (anInvocation.selector == @selector(sayHello)) {
        HTCommon *common = [[HTCommon alloc] init];
        anInvocation.target = common;
        return [anInvocation invoke];
    }
    return [super forwardInvocation:anInvocation];
}

#pragma mark- 处理类方法
+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    
    NSLog(@"%s -- %@", __func__, NSStringFromSelector(aSelector));
    if (aSelector == @selector(sayBye)) {
        return [NSMethodSignature signatureWithObjCTypes:"v:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

+ (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"%s -- %@", __func__, NSStringFromSelector(anInvocation.selector));
}

如果methodSignatureForSelector的返回值是NSMethodSignature对象,则会调用forwardInvocation方法对anInvocation事务进行处理,如果不处理也不会报错

消息转发总结

消息转发的处理主要分为两部分:

方法调用流程

image

总结

至此,objc_msgSend发送消息的流程就分析完成了,我们可以得出整个方法调用的流程:

缓存cache快速查找流程 --> 慢速查找流程 --> 动态决议方法resolveInstanceMethod --> 快速转发流程forwardingTargetForSelector --> 慢速转发流程(methodSignatureForSelector) --> resolveInstanceMethod --> forwardInvocation --> 崩溃报错

补充

hopper反汇编CoreFoundation系统库

查看崩溃时的堆栈信息,调用了CoreFoundation系统库的forwarding_prep_0___forwarding___方法,如下图

image

下载CoreFoundation源码,并没有找到这两个方法的实现,说明这块内容苹果并没有对外提供,只是开源了部分CoreFoundation源码

image image

forwarding_prep_0方法

全局搜索__forwarding_prep_0___,发现只有一个,且会调用__forwarding__

image

____forwarding___方法

image image image
上一篇 下一篇

猜你喜欢

热点阅读