天天看点

关于IOS一些有的没的 – IOS Runtime机制

IOS Runtime机制

在没有接触这个概念,或者只是听说这个概念的时候,我整个人觉得特别抽象,然后从各大博客,各大网站了解之后发现还是没有什么进展,
一下有一些笔记也不记得出自哪里了,各位大牛如果冲撞了各位,通知后我自会删除,谢谢!
           
  • Runtime机制为什么存在?

    OC是动态语言,也就是说它自己好多决定性的工作都不是编译的时候做的而是延迟到了运行时,而这样也就导致了仅仅是编译器是不够的,需要一个运行时系统(即Runtime system)来进一步执行编译后的代码.

    简单来说   OC代码 ---> 编译后 --->运行时系统执行
               
  • Runtime版本

    简单地提一笔modern和legacy,区别啊,联系啊什么的可以去网上查找 ;ps:Runtime是由C和会编写的(为了动态系统高效)

- Runtime术语的数据结构

1) SEL:方法选择器

typedef struct objc_selector *SEL;
           
我们比较熟悉的是OC: @selector(),其实就是能够通过它找到方法实现的一个C字符串,而在Runtime里边有一个sel_registerName,
这两个函数都能获取一个SEL类型的方法选择器

PS:A和B类有同一个方法meetSm();他们对应的selector是相同的,只是变量的类型不同,一个是A类一个是B类所以不会导致混乱
           

2) id:参数类型 指向某个类的实例

typedef struct objc_object *id;
            struct objc_object{
                Class isa;
            };
           
PS:通过isa指针可以找到所属的类,但是它在代码运行时不总指向实例对象所属的类型,KVO中得观察对象的isa就指向一个中间类
           

3) Class: 指向objc_class结构体的指针

/*以下代码不规范,只是捡着重要的属性显示和说明*/
            typedef struct objc_class *Class;
            struct objc_class{
                Class isa; //ObjC类本身也是个对象,指针指向所属类
                Class super_class;//父类指针
                const char *name;//类名
                ...
                struct objc_ivar_list *ivars;//成员变量列表
                struct objc_method_list **methodLists;//方法列表
                struct objc_cache *cache;//缓存
                struct objc_protocol_list *protocols;//附属协议
            }OBJC2_UNAVALABLE;
           
***类与对象***

对于Class其中 isa中提到类本身也是个对象怎么理解?
    其实为了处理类和对象的关系,Runtime库创建了一个叫做Meta Class的玩意叫做元类

那元类是干啥的呢?
    首先举个例子: 我们都知道方法分类方法和对象方法,对象方法需要实例调用,类方法是通过类名调用,而实际上类方法也是一个对象来调用的
    这个对象不同于实例对象他是类对象

那类对象是干什么的呢?
    不同于实例,每个类只有一个类对象,而类对象所属的类就是元类即Meta Class,并且每个类对象仅有一个与其相关的元类(一一对应),我们是
    从类方法出发得到这样的结论的其实类方法则来自Meta Class

既然知道了类对象,元类,那么再介绍一个概念--根元类(Root Meta Class),其实元类是根元类的一个实例,那再往下抛一层根元类的父类
即NSObject,而在往下抛NSObject没有父类,再然后我也不知道了哈哈哈...

总结: 有一个实例对象 a -- > 类A(类对象A元类的实例) -- > 元类(根元类的实例) -- > 根元类 -- > NSObject
           
**成员变量列表**
Class 中有属性ivars 和methodLists 结构体为objc_ivar_list和objc_method_list为了省地方就不写内容了简单介绍下重点的东西
    objc_ivar_list中包含 int ivar_count; 变量个数  struct objc_ivar ivar_list[1];存储单个变量的信息
           

4) Ivar 和Method:在上面的Class中有变量列表和方法列表的结构体,其中包含了两种结构体分别为: objc_ivar 和 objc_method 下边来分别短暂得介绍下

typedef struct objc_ivar *ivar;  //-->Ivar 成员变量的类型
            struct objc_ivar{
                char * ivar_name;//属性名称
                char *ivar_type;//属性类型
                int ivar_offset;//基地址偏移字节(其实我也不知道相对于谁?大学的知识还给了我敬爱的老师)
            };

            typedef struct objc_method *Method; // -->Method 代表类中的某个方法
            struct objc_ivar{
                SEL method_name;//方法名 .类型为SEL
                char *method_type;//方法类型,存储参数和返回值的类型
                IMP method_imp;//函数指针,指向函数的实现
            };
           

5) IMP:在上边的Method中看到了IMP method_imp 是一个函数指针指向函数的实现

typedef id(*IMP)(id, SEL, ...);
            //IMP是编译器生成的;
            //IMP指向-->最终执行的代码(即方法的实现不是ObjC的消息);
            //如果得到了某个实例的某个方法的入口,就可以绕过消息传递,直接执行;
           
PS:解释一下它的参数id 和SEL.首先举个栗子:
    例如:[objectA sendTheMessage];这个方法---运行时被编译器转化为--->objc_msgSend(objectA, sendTheMessage);
    其实IMP指向的方法与objc_msgSend函数的类型相同,并且可以看到他们参数都包含id 和 SEL参数;
           

6) Cache:其实在大学的时候单片机的时候计算机原理的时候都遇到过这个东东,其中有一条就是CPU会绕过主存先访问Cache(性能)其实IOS中Cache也一样,先简单来看一下:

typedef struct objc_cache *Cache;
            struct objc_cache{
                ...
            };
            //(包含一些我也不知道的东西,我也没有仔细查,反省中......)
           
简单地讲一下Cache的作用就好了:

    你天天去买大白菜,老是去买,卖东西的老板娘一见到你本能的就知道你要买大白菜,他没有过脑子,如果我把脑子比作计算机的主存,也比作
    Class中的那个方法列表的话,如果我总是调用一个方法A(大白菜),就不用去脑子找了,直接从Cache(记忆中,本能中)获得方法的实现(例子可能不太生动);
    其实当一个实例a接收到一个消息它不会去isa 指针指向的类Class中找到方法列表然后遍历查找到能够响应的那个方法的,因为效率
    太低了,Runtime系统吧调用的方法存到Cache中,则其实他是先到Cache中查找再去列表中找,再找不到去父类的列表中找再找不到就涉及到消息中的动态方法解析了

过程就是:
    a收到消息-->Cache去找实现方法-->找不到去方法列表找-->找不到去父类方法列表找-->NSObject还找不到-->开始进入动态解析
           

7) Property:并不想介绍 属性

typedef  struct  objc_property * Property;
            typedef  struct  objc_property * objc_property_t;//(更常用)
            //而怎么获取这些属性呢?方法有:
            objc_property_t  *class_copyPropertyList(Class class, unsigned int *outCount); //获取类中的属性
            objc_property_t  *protocol_copyPropertyList(Protocol *protocol, unsigned int *outCount );//获取协议中的属性
           
PS:class_copyPropertyList和protocol_copyPropertyList返回的是属性列表中的每个元素都是一个objc_property_t指针,好吧再举
个栗子吧:
    有个类叫 A,有三个属性A_a ,A_b,A_c 则如果我们要获取它的类中的方法则:
    unsigned int outCount = 0;
    objc_property_t *properties_A = class_copy_List([A class], &outCount); 
    outCount -- > 属性个数3;
    property_getName -- > 获取类名;
    property_getAttributes -- > 获得属性的真实名称_A_a和@encode类型返回c字符串;
           

-未完待续(见下一)