美文网首页
objc_msgSend学习

objc_msgSend学习

作者: Tony17 | 来源:发表于2020-02-28 08:31 被阅读0次

    前言

    OC的方法调用,其实就是通过objc_msgSend函数的调用。通过对 objc_msgSend 执行过程中的一些处理,我们可以达到防御unrecognized selector sent to instance问题,也可以像著名的开源库 Aspect那样做到在已知方法中插入代码或者直接替换已知方法的实现。

    objc_msgSend 流程

    objc_msgSend的执行流程分为三大阶段:

    1. 消息发送
    2. 动态方法解析
    3. 消息转发
    4. 报错 unrecognized selector sent to instance
    objc_msgSend-消息发送.png
    objc_msgSend-动态解析.png
    objc_msgSend-消息转发.png

    相关代码实现:

    +resolveInstanceMethod:或者+resolveClassMethod:方法

    + (BOOL)resolveInstanceMethod:(SEL)sel {
        Method method = class_getInstanceMethod(self, @selector(errorSelector));
        class_addMethod([self class], sel, method_getImplementation(method), method_getTypeEncoding(method));
        return [super resolveInstanceMethod:sel];
    }
    
    + (BOOL)resolveClassMethod:(SEL)sel {
        Method method = class_getInstanceMethod(self, @selector(errorSelector));
        class_addMethod([self class], sel, method_getImplementation(method), method_getTypeEncoding(method));
        return [super resolveInstanceMethod:sel];
    }
    

    forwardingTargetForSelector:方法, 该方法分为实例方法和类方法,对应不同的方法调用。返回值也要区分是类对象还是实例对象。

    - (id)forwardingTargetForSelector:(SEL)aSelector {
        return [ErrorSelector new];
    }
    
    + (id)forwardingTargetForSelector:(SEL)aSelector {
        return [ErrorSelector class];
    }
    

    methodSignatureForSelector:forwardInvocation:方法, 该方法分为实例方法和类方法,对应不同的方法调用。方法内部的处理可以是一样的,不用区分类和实例的区别。

    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        // 方法签名就是方法的返回值类型,参数类型
        NSMethodSignature *sign = [NSMethodSignature signatureWithObjCTypes:"v@:"];
        return sign;
    }
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
        // NSInvocation 封装了一个方法调用,包括:方法调用者,方法名,参数
        [anInvocation invokeWithTarget:[[ErrorSelector alloc]init]];
    }
    + (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        // 方法签名就是方法的返回值类型,参数类型
    //    NSMethodSignature *sign = [NSMethodSignature signatureWithObjCTypes:"v@:"];
        NSMethodSignature *sign = [[ErrorSelector new] methodSignatureForSelector:@selector(errorSelector)];
        return sign;
    }
    + (void)forwardInvocation:(NSInvocation *)anInvocation {
        // NSInvocation 封装了一个方法调用,包括:方法调用者,方法名,参数
        [anInvocation invokeWithTarget:[[ErrorSelector alloc]init]];
    }
    

    最后

    以上就是本篇的内容,势必会有遗漏的地方,欢迎斧正~

    相关文章

      网友评论

          本文标题:objc_msgSend学习

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