objc_msgSend执行流程

objc_msgSend执行流程

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

  1. 消息发送
  2. 动态方法解析
  3. 消息转发

1.消息发送

objc_msgSend执行流程
上图就是消息发送阶段的过程,如果查找到最顶级的类,仍然没有找到相应的方法,则会进入下一个阶段

2. 动态方法解析

objc_msgSend执行流程
我们在这一步中动态添加的方法,是添加到当前类/当前元类 的class_rw_t表中,调用之后,方法会缓存在cache表中 (cache表底层是通过散列表实现的,效率高,这里散列表的大概实现原理是通过key值&MASK得到一个序号(这个序号可能是相同,可能不是放在首位),这样通过序号可以直接找到当前存储的对象,通过key拿到value)

// 动态添加实例方法,添加的方法存在对象的方法列表中
+ resolveInstanceMethod: 
  1. 在程序运行阶段动态添加一个实例方法
struct method_t {
    SEL sel;
    char *types;
    IMP imp;
};

- (void)testABC {
    NSLog(@"%s",__func__);
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    
    if (sel == @selector(test)) {
        
        struct method_t *method = (struct method_t *)class_getInstanceMethod(self, @selector(testABC));
        
        class_addMethod(self, sel, method->imp, method->types);
        
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
}

还可以这么写

- (void)testABC {
    NSLog(@"%s",__func__);
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    
    if (sel == @selector(test)) {
        
        Method method = class_getInstanceMethod(self, @selector(testABC));
        
        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
        
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
}
  1. 在程序运行阶段动态添加一个类方法
+ (BOOL)resolveClassMethod:(SEL)sel {
    if (sel == @selector(test)) {
        
        Method method = class_getInstanceMethod(self, @selector(other));
        
        // 这里是往元类中添加方法,所以需要通过object_getClass获取元类
        class_addMethod(object_getClass(self), sel, method_getImplementation(method), method_getTypeEncoding(method));
        
        return YES;
    }
    return [super resolveClassMethod:sel];
}

3. 消息转发

objc_msgSend执行流程

消息转发

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    if (aSelector == @selector(test)) {
        // 交给student类处理
        return [[MJStudent alloc] init];
    }
    // 如果这里不处理的话,走方法 methodSignatureForSelector:
    return [super forwardingTargetForSelector:aSelector];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    if (aSelector == @selector(test)) {
        // 如果这里处理了,会走方法 forwardInvocation:
        // [email protected]:8 是方法签名
        return [NSMethodSignature signatureWithObjCTypes:"[email protected]:8"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    // 这里可以随意处理
}