美文网首页
runtime(实现iOS 语言动态的一组API)

runtime(实现iOS 语言动态的一组API)

作者: CrystalZhu | 来源:发表于2020-02-07 16:24 被阅读0次

    runtime的所有知识基本都是围绕两个中心:

    1.类的各个方面的动态配置

    动态创建类,动态地为类添加属性和方法,动态绑定,动态加载.
    

    2.消息传递

    调用方法时@selector(方法名)只是SEL指针,SEL指针只是方法编号,在运行时,才会根据SEL和id也就是调用方法的对象获得IMP指针,确定执行的方法.
    

    类的本质(定义):

    struct objc_class{
        class isa OBJC_ISA_ACAILABILITY;  *指向其类的isa指针
        class super_class;  *父类
        const char *name;  *类名
        long version;  *类版本信息,默认为0
        long info;  *类信息,供运行期间使用的一些位标识
        long instance_size;  *类的实例变量大小
        struct objc_ivar_list *ivars;  *类的成员变量链表
        struct objc_method_list **methodlists;  *方法链表
        struct objc_cache  *cache;  *方法缓存
        struct objc_protocol_list *protocols; *协议链表
    }
    OC中类是由class类型来表示的,实际上它是一个指向objc_class的结构体
    

    不同的类中可以有相同的方法,同一个类中不可以有相同的方法,判断是不是同一个方法只和方法名有关,与参数无关.

    属性概念

    SEL: 类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是保存方法的编号.
    IMP:一个函数指针,保存了方法的地址.
    method:方法的结构体,其中保存了方法的名字,实现和类型描述字符串
    

    每个继承于NSObject的类都能自动获得runtime的支持,在这样一个类中,有一个isa指针,指向该类定义的数据结构体,这个结构体是由编译器,编译时为类创建的,在这个结构体中包括了指向其父类类定义的指针以及Dispatch table, Dispatch table是一张SEL和IMP的对应表.

    要找到方法首先要确定是哪个类,isa和super_class是找到实现函数的关键映射,决定找到存放在哪个类的方法实现(isa用于自省确定所在类,super_class确定继承关系)

    过程:

    同一个Object-C对象发送消息时,运行时会根据实例对象的isa指针找到这个实例对象所属的类,runtime库会在类的方法列表由super_class指针找到父类的方法列表直到根类NSObject中去寻找与消息对应的selector指向的方法,找到后即运行这个方法
    

    继承层次中字类,父类,根类,以及其对应metaclass(元类)的isa与super_class直接的关系:

    1. 类的实例对象的isa指向该类;该类的isa指向该类的metaclass
    2.类的super_class指向其父类,若该类为根类则值为NULL;
    3.metaclass的isa指向根metaclass,若该metaclass是根metaclass则指向自身.
    4.metaclass的super_class指向父metaclass,若该metaclass是根metaclass则指向该metaclass对应的类.
    

    方法的存储位置

    每个类的方法列表都存储在类对象中,每个方法都有一个与之对应的SEL类型的对象,根据一个SEL对象,就可以找到方法的地址进而调用方法.

    SEL类型的定义
    typedef struct objc_selector *SEL;
    IMP(implement)类型的定义
    typedef id(* IMP) (id, SEL, ...);
    IMP是一个函数指针,这个被指向的函数包含一个接收消息的对象id(self指针)调用方法的SEL(方法名)以及不定个数的方法参数,并返回一个id;
    IMP是消息最终调用的执行代码,是方法真正的实现代码
    SEL和IMP其实就实现了多态,一个SEL指向不同的函数指针,完成了一个方法名在不同时候执行不同的函数体.

    Q1:获取方法编号

    @selector就是取类方法的编号
    SEL methodId = @selector(func1);
    SEL methodId2 = NSSelectorFromString(@“test”);
    

    Q2:执行对应方法

    [self performSelector: methodId withObject: nil];
    

    Q3:通过编号获取方法

    NSString *methodName = NSStringFromSelector(methodId);
    

    Q4:IMP怎么获取和使用

    IMP methodPoint = [self methodForSelector: methodId];
    methodPoint()  //使用
    

    相关文章

      网友评论

          本文标题:runtime(实现iOS 语言动态的一组API)

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