您的位置:首页 > 移动开发 > IOS开发

iOS 编码复习(二)—— runtime

2016-02-24 16:11 169 查看
最近特意看了很多篇关于runtime的文章。所以自己也想把了解的东西总结一下,以便以后大家一起学习。首先必须要诚实地说一句,这里都是看了别人的文章后,用自己的话总结出来的,而没有像其他额大牛样去用c语言去写一个swizzle method之类的。

首先要说,OC是一门运行时语言,因为它不像c++在编译的时候就会检查所有函数调用,而是运行时才会检查。

先来看看[target dosomething:varl];编译器会把它编译成什么:objc_msgsend(target,@selector(dosomething:),varl);你会发现这是一个c方法。那什么是runtime呢?runtime其实就是一个运势时的c语言写成的基础库,oc的程序必须得到runtime的的运行才能正常work。

下面我们来介绍一下对象和类。它们其实就是用c语言封装的结构体。(感受下面向对象与面向过程语言的区别)

oc里的class实际上就是一个objc_class结构体的指针:

typedef struct objc_class *Class;


struct objc_class {

Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__

Class super_class                       OBJC2_UNAVAILABLE;  // 父类

const char *name                        OBJC2_UNAVAILABLE;  // 类名

long version                            OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0

long info                               OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识

long instance_size                      OBJC2_UNAVAILABLE;  // 该类的实例变量大小

struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 该类的成员变量链表

struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表

struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法缓存

struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表

#endif

} OBJC2_UNAVAILABLE;

上图就是objc/runtime.h中objc_class 类的结构体的定义

其中以下参数是我们需要注意的:

1 isa:这个isa指向它所属的类,在运行时就靠这个指针来检测这个对象是否可以响应一个selector;需要注意的是在objective-c中,所有类自身也是一个对象,这个对象的class里面也有一个isa指针,它指向metaClass(元类 )。

2 super_class: 指向该类的父类,如果该类已经是最顶层的根类,则super_class为NULL;

3 cache:用于缓存最近使用的方法,一个接受者对象接受一个消息时,它会根据isa指针去查找能够响应这个消息的对象,有了这个缓存,每次调用runtime时,它就不需要每次都去方法链表中查找一边所有的方法,而是先去cache中进行查找;

好,我们来举个例子

NSArray * array = [[NSArray alloc] init];

其流程就是:

1、[NSArray alloc]先被执行,因为NSArray没有+alloc方法,于是就去父类NSObject中查找。

2、检测NSObject是否响应+alloc方法,发现响应,于是检测NSArray类,并根据其所需的内存空间大小开始分配内存空间,然后把isa指针指向NSArray类。同时,+alloc也被加进cahce;列表里。

3、接着,执行-init方法,如果NSArray响应该方法,则直接将其加入cache。如果不响应,则去父类查找。

4、在后期的操作中,如果再以[[NSArray alloc]init]这种方式创建数组的话,则会直接从cache中取出相应的方法,直接调用。

(更深层次的就不多说了,可以看这个链接的东西 http://southpeak.github.io/blog/2014/10/25/objective-c-runtime-yun-xing-shi-zhi-lei-yu-dui-xiang/

objc_object与id

struct objc_object {

Class isa  OBJC_ISA_AVAILABILITY;

};

typedef struct objc_object *id;

objc_object是表示一个类的实例的结构体,如上定义:

这里我们可以看到它只有一个指向其class 的isa指针。这样,当我们向一个对象发送消息时,runtime库(objc/runtime.h)就会根据isa指针找到相应的类。同时会在当前类的方法链表及其父类的列表方法中去寻找与selector指向对应的方法。

id,它就是一个objc_object结构类型的指针,它的存在可以让我们实现类似c++泛型的操作,有点类似void*指针类型的作用。

元类(meta Class)

上面我们提到,所有类自身也是一个对象,我们可以向这个对象发送消息(调用类方法)。

[NSArray array];

这里+array消息发送给了NSArray类,而这个NSArray也是一个对象。既然是对象,那么它也是一个objc_object指针,它包含一个指向其类的isa指针,那么isa指针指向哪里呢?为了调用+array,这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体。这就是meta-class ——是一个类对象的类。

当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class的方法中查找。meta-class会存储着一个类的所有类方法。每个类都会有一个独立的meta-class。meta-class也是一个类,那么它的isa指向什么呢?所有的isa指针都指向基类的meta-class。如,所有的NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己的所属类,而meta-class的isa指针是指向它自己。

可以使用

objc_getClass((__bridge
void*)[UIViewController
class])

获取meta-class的指针地址。
OK,在讨论完这些底层数据结构之后,我们就可以来看看我们代码当中的具体使用了:

具体的以后有时间再解析:其实runtime无处不在,比如属性的使用KVC、消息和方法的使用@selector、对分类和协议的支持、block等!想要了解更多更详细的内容可以去刚才的那个网址仔细阅读。后续我也会把自己整理的东西陆续更新。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  iOS runtime