iOS底层原理之消息发送

OC中的方法调用,其实都是转化为objc_msgSend函数的调用,objc_mesgSend的执行流程可分为3个阶段

  • 消息发送
  • 动态方法解析
  • 消息转发

消息转发

iOS底层原理之消息发送_第1张图片
消息转发的流程图

动态方法解析

iOS底层原理之消息发送_第2张图片
动态方法解析

开发者可以实现以下的办法来实现动态添加方法实现

  • +resolveInstanceMethod:
  • +resolveClassMethod:

动态解析后会重新走消息发送的流程,从receiveClasscache中查找方法这一步开始执行

创建一个Person类,然后在.h文件中写一个- (void)test,但是不写具体实现,然后调用.会打印出最常见的unrecognized selector sent to instance.

- (void)other{
NSLog(@"%s",__func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(test)) {
//获取其他方法
Method method = class_getInstanceMethod(self, @selector(other));
//动态添加test的方法
class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
}
return [super resolveInstanceMethod:sel];
}

消息转发

如果一个方法在消息发送阶段没有找到相关方法,也没有进行动态方法解析,这个时候就会走到消息转发阶段了.

iOS底层原理之消息发送_第3张图片
消息转发

forwardingTargetForSelector

创建两个类Person和Student,在Person.h里面写一个实例方法,但是不去实现相关方法。

在Person里面实现这个方法
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(test)) {
        return [[Student alloc]init];
    }
    return nil;
}

调用forwardingTargetForSelector,返回值不为nil时,会调用objc_msgSend(返回值, SEL),结果就是调用了objc_msgSend(Student,test)

methodSignatureForSelector(方法签名)

forwardingTargetForSelector返回值为nil,或者都没有调用该方法的时候,系统会调用methodSignatureForSelector方法。调用methodSignatureForSelector,返回值不为nil,调用forwardInvocation:方法;返回值为nil时,调用doesNotRecognizeSelector:方法

对于方法签名的生成方式

  • [NSMethodSignature signatureWithObjCTypes:"i@:i"]
  • [[[Student alloc]init] methodSignatureForSelector:aSelector];
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(test)) {
        return [[[Student alloc]init]methodSignatureForSelector:aSelector];
       // return [NSMethodSignature signatureWithObjCTypes:"i@:i"];
    }
    return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"=======");
}

NSInvocation中封装了一个方法调用,包括方法调用者,方法名,方法参数.

  • anInvocation.target 方法调用者
  • anInvocation.selector 方法名
  • [anInvocation getArgument:NULL atIndex:0]

你可能感兴趣的:(iOS底层原理之消息发送)