美文网首页
objc_msgSend执行流程

objc_msgSend执行流程

作者: love断鸿 | 来源:发表于2021-05-31 18:17 被阅读0次

    OC中的方法调用,其实都是转换为objc_msgSend函数的调用

    objc_msgSend的执行流程可以分为3大阶段

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

    流程如下:


    WechatIMG122.png

    备注:

    • 在class_rw_t查找方法时,如果已经排序的,则二分查找提高效率, 如果没有排序的,遍历查找
    • receiver通过isa指针找到receiverClass
    • receiverClass通过superclass指针找到superClass
    2.动态方法解析
    流程如下 WechatIMG123.png
    • 动态解析过后,会重新走“消息发送”的流程“从receiverClass的cache中查找方法”这一步开始执行

    示例
    +resolveInstanceMethod:
    +resolveClassMethod:
    在上述两个方法中防止崩溃

    @interface ClassA : NSObject
    - (void)test;
    @end
    
    #import "ClassA.h"
    #import <objc/runtime.h>
    @implementation ClassA
    
    - (void)other {
        NSLog(@"在.m里没有实现test方法 正常情况下会报错, 但是在resolveInstanceMethod进行了处理就不会有问题了");
    }
    
    // 没找到对象方法的时候调用这个
    + (BOOL)resolveInstanceMethod:(SEL)sel {
        if (sel == @selector(logAAA)) {
            // 创建一个方法
            Method otherMethod = class_getInstanceMethod(self, @selector(other));
            
            class_addMethod(self, sel,
                            // 之前定义方法的实现
                            method_getImplementation(otherMethod),
                            // types
                            method_getTypeEncoding(otherMethod));
            return YES;
        }
        
        return  [super resolveInstanceMethod:sel];
    }
    @end
    
    

    3.消息转发阶段

    当实现过 2动态方法解析阶段, 会进入消息转发阶段


    WechatIMG127.png

    相关代码

    - (id)forwardingTargetForSelector:(SEL)aSelector {
        
        return [super forwardingTargetForSelector:aSelector];
    }
    
    // 返回方法签名: 返回值类型, 参数类型
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        if (aSelector == @selector(test)) {
            return [NSMethodSignature signatureWithObjCTypes:@"v20@0:i16"];
        }
        return [super methodSignatureForSelector:aSelector];
    }
    
    // NSInvocation 封装了一个方法调动, 包括 方法调用者, 方法名, 方法参数
    // anInvocation.selector 方法名
    // anInvocation.target 方法调用者
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
        // 在这里修改 target 和selecor 从而实现消息发送
        anInvocation.target = [[ClassC alloc]init];
        anInvocation.selector = @selector(classCTest);
        [aninvocation invoke];
    }
    
    
    注意: 类方法的 消息转发阶段 全都是+方法

    [self class] 和[super class]

    1:底层实现

    // self
    objc_msgSend
    
    // super
    objc_msgSendSuper(self, @selector(class))
    

    2:self和super的消息接收者都是当前类 例如, [self class]和 [super class] 消息接收者都是self 但是查找层级不同 self 从当前类查找, super 从父类查找

    3: class 方法虽然每个oc对象都有声明, 但是具体实现是在NSObject里面

    NSObject中class的实现 大体是

    - (Class)class 
    {
       return object_getClass(self);
    }
    
    - (Class)superClass 
    {
       return object_getSuperclass(self);
    }
    

    结论: 由源码可以看出 class和superClass 的消息接收者都是self

    迁移

    @interface Person : NSObject
    
    @end
    
    @interface Student : Person
    
    @end
    
    @implementation Student
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            NSLog(@"%@", [self class]);  Student
            NSLog(@"%@", [self superclass]); Person
    
            NSLog(@"%@", [super class]); Student
            NSLog(@"%@", [super superclass]);   Person     
        }
        return self;
    }
    
    @end
    
    

    上述示例中, 无论 suerp 还是self 他们的class 和superClass 方法的实现都在 NSObject当中, 所以他们的消息接收者都是self, 只不过super 是从Person开始查找, self 是从Student中开始查找

    相关文章

      网友评论

          本文标题:objc_msgSend执行流程

          本文链接:https://www.haomeiwen.com/subject/aqtcsltx.html