美文网首页
Runtime知识点整理3

Runtime知识点整理3

作者: 化二缺 | 来源:发表于2020-05-25 08:44 被阅读0次

    objc_msgSend

    实现源码是汇编 为了效率
    方法查找是用C++ 找到IMP 填充到当前对象里 然后 就返回到汇编

    [person personTest];
    objc_msgSend(person,@selector(personTest))
    消息接受者(receiver): person
    消息名称: personTest

    • objc_msgSend的执行流程可以分为3大阶段
    • 消息发送
    • 动态方法解析
    • 消息转发

    最后如果找不到会报错:unrecognized selector sent to instance

    消息发送阶段

    消息发送.png

    动态方法解析 阶段

    平时开发的时候用不到 主要就是面试

    #import "YZPerson3.h"
    #import <objc/runtime.h>
    @implementation YZPerson3
    struct method_t {
        SEL sel ;
        char * types;
        IMP imp;
    };
    
    -(void)retryOther{
        NSLog(@"retryOther %s", __func__);
    }
    
    + (BOOL)resolveInstanceMethod:(SEL)sel{
        
        if(sel == @selector(persontest)){
         //获取其他方法
           // struct method_t * method = (struct method_t *)class_getInstanceMethod(self, @selector(retryOther));
            Method method = class_getInstanceMethod(self, @selector(retryOther));
            
            
            //动态添加方法
           // class_addMethod(self, sel, method->imp, method-> types);
            class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
        }
        
        return  YES;
        
    }
    @end
    
        YZPerson3 * person = [[YZPerson3 alloc]init];
        
        //必须在h文件写上名字 
        [person persontest];
    
    c语言方式.png
    动态方法解析 流程.png
    image.png

    消息转发 阶段

    消息转发 阶段.png

    代码示例

    • 这里是对象方法 如果要用到 类方法类似+test 需要用 + forwordInvocation:方法
    @interface YZPerson4 : NSObject
    -(void)test:(int)age;
    @end
    
    #import <objc/runtime.h>
    @implementation YZPerson4
    //这里有对应的+方法 因为底层是用receiver 直接调用的名字
    -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
        
        if (aSelector == @selector(test:)) {
            return  [NSMethodSignature signatureWithObjCTypes:"v@:i"];
        }
        return  [super methodSignatureForSelector:aSelector];
    }
    //这里有对应的+方法 因为底层是用receiver 直接调用的名字
    - (void)forwardInvocation:(NSInvocation *)anInvocation{
        //参数顺序 receiver selector other arguments
        int age ;
        [anInvocation getArgument:&age atIndex:2];
        
        NSLog(@"age + 10 = %d",age + 10);
        
    }
    @end
    

    NSInvocation 对象

    • NSInvocation 文件里有关于方法签名的 枚举
    enum _NSObjCValueType {
        NSObjCNoType = 0,
        NSObjCVoidType = 'v',
        NSObjCCharType = 'c',
        NSObjCShortType = 's',
        NSObjCLongType = 'l',
        NSObjCLonglongType = 'q',
        NSObjCFloatType = 'f',
        NSObjCDoubleType = 'd',
        NSObjCBoolType = 'B',
        NSObjCSelectorType = ':',
        NSObjCObjectType = '@',
        NSObjCStructType = '{',
        NSObjCPointerType = '^',
        NSObjCStringType = '*',
        NSObjCArrayType = '[',
        NSObjCUnionType = '(',
        NSObjCBitfield = 'b'
    } API_DEPRECATED("Not supported", macos(10.0,10.5), ios(2.0,2.0), watchos(2.0,2.0), tvos(9.0,9.0));
    

    @dynamic

    • 告诉编译器不用自动生成getter 和setter 的实现,等到运行时再添加方法实现
    • 了解下算了

    相关文章

      网友评论

          本文标题:Runtime知识点整理3

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