Objective-C Runtime 总结:类和对象 篇

来源:互联网 发布:网络情歌 编辑:程序博客网 时间:2024/06/05 02:35

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等。

这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来 (runtime system)执行编译的代码。
对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc Runtime。Objc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。这就是 Objective-C Runtime 系统存在的意义,它是整个Objc运行框架的一块基石。

这就是 Objective-C Runtime 系统存在的意义,它是整个Objc运行框架的一块基石。

Runtime库主要做下面几件事:
封装:在这个库中,对象可以用C语言中的结构体表示,而方法可以用C函数来实现,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法了。
找出方法的最终执行代码:当程序执行[object doSomething]时,会向消息接收者(object)发送一条消息(doSomething),runtime会根据消息接收者是否能响应该消息而做出不同的反应。这将在后面消息机制中详细介绍。

现在我们先来研究下OC中的对象模型,在oc中对象可以用C语言中的结构体表示。

一:id

在oc中,所有的对象都可以用id类型表示,包括NSObject和非NSObject对象(如NSProxy,它是个抽象超类,它实现了一些消息转发有关的方法),它是一个指向类实例的指针,在oc中的定义如下:

typedef struct objc_object *id;

可以看出id是一个指向objc_object结构体的指针,
那objc_object又是啥呢:

struct objc_object { Class isa; };

objc_object结构体包含一个isa指针,根据isa指针指向Class(类对象),下面我们看看Class具体是什么

二.Class类对象

Objective-C类是由Class类型来表示的,Class类对象保存这该类的实例变量和实例方法等信息,下面我们看看Class的定义:

typedef struct objc_class *Class;

可看出它实际上是一个指向objc_class结构体的指针,
查看objc/runtime.h中objc_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;

在这个定义中,下面几个字段是我们感兴趣的

  1. isa:需要注意的是在Objective-C中,所有的类自身也是一个对象,所以我们也把Class叫类对象,这个对象的Class里面也有一个isa指针,它指向metaClass(元类),我们会在后面介绍它。
  2. super_class:指向该类的父类,如果该类已经是最顶层的根类(如NSObject或NSProxy),则super_class为nil。
  3. cache:用于缓存最近使用的方法。一个接收者对象接收到一个消息时,它会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有一部分方法是常用的,很多方法其实很少用或者根本用不上。这种情况下,如果每次消息来时,我们都是methodLists中遍历一遍,性能势必很差。这时,cache就派上用场了。在我们每次调用过一个方法后,这个方法就会被缓存到cache列表中,下次调用的时候runtime就会优先去cache中查找,如果cache没有,才去methodLists中查找方法。这样,对于那些经常用到的方法的调用,但提高了调用的效率。
  4. version:我们可以使用这个字段来提供类的版本信息。这对于对象的序列化非常有用,它可是让我们识别出不同类定义版本中实例变量布局的改变。

下面说说Class里的isa,它指向了该类的元类

三、元类(Meta Class)

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

NSArray *array = [NSArray array];

这个例子中,+array消息发送给了NSArray类,而这个NSArray也是一个对象。既然是对象,那么它也是一个objc_object指针,它包含一个指向其类的一个isa指针。那么这些就有一个问题了,这个isa指针指向什么呢?为了调用+array方法,这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体。这就引出了meta-class的概念

meta-class是一个类对象的类。

当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class的方法列表中查找

再深入一下,meta-class也是一个类,也可以向它发送一个消息,那么它的isa又是指向什么呢?为了不让这种结构无限延伸下去,Objective-C的设计者让所有的meta-class的isa指向基类的meta-class,以此作为它们的所属类。即,任何NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己的所属类,而基类的meta-class的isa指针是指向它自己。这样就形成了一个完美的闭环。

通过上面的描述,再加上对objc_class结构体中super_class指针的分析,我们就可以描绘出类及相应meta-class类的一个继承体系了,如下图所示:
这里写图片描述

对于NSObject继承体系来说,其实例方法对体系中的所有实例、类和meta-class都是有效的;而类方法对于体系内的所有类和meta-class都是有效的。

例子:

首先创建两个类分别为AB:
A类继承NSObject:

@interface A : NSObject@end

B类继承A:

@interface B : A@end 

设置代码打印类信息:

Class bClass=objc_getClass("B");//获取B的类对象//0x10a012778,Name:B    NSLog(@"class:%p,Name:%s",bClass,class_getName(bClass));    Class superClass=class_getSuperclass(bClass);//获取父类,A //0x10a012818 Name:A    NSLog(@"class's superClass:%p Name:%s",superClass,class_getName(superClass));    //获得父类NSObject,这里是根类了    Class rootClass=class_getSuperclass(class_getSuperclass(bClass));//0x10a732d28,Name:NSObject    NSLog(@"RootClass's superClass:%p,Name:%s",rootClass,class_getName(rootClass));    //根类的父类为nil    Class rootSuperClass=class_getSuperclass(rootClass);//0x0,Name:nil    NSLog(@"rootSuperClass:%p,Name:%s",rootSuperClass,class_getName(rootSuperClass));    NSLog(@"================meta class===============");    //在一个类对象调用class方法是无法获取meta-class,它只是返回类而已    NSLog(@"B metaClass:%p",objc_getMetaClass("B"));    NSLog(@"B superMetaClass:%p",class_getSuperclass(objc_getMetaClass("B")));    NSLog(@"A metaClass:%p",objc_getMetaClass("A"));    NSLog(@"A superMetaClass:%p",class_getSuperclass(objc_getMetaClass("A")));    NSLog(@"root metaClass:%p",objc_getMetaClass("NSObject"));    //根元类的父类为自己的类对象rootClass    Class rootMetaSuperClass=class_getSuperclass(objc_getMetaClass("NSObject"));//0x10a732d28,Name:NSObject    NSLog(@"rootSuperMetaClass:%p,Name:%s",rootMetaSuperClass,class_getName(rootMetaSuperClass));

运行后,打印结果是

2015-12-23 18:09:42.055 RuntimeTest[1107:123501] class:0x10e503a40,Name:B2015-12-23 18:09:42.056 RuntimeTest[1107:123501] class's superClass:0x10e503ae0 Name:A2015-12-23 18:09:42.056 RuntimeTest[1107:123501] RootClass's superClass:0x10ec24d28,Name:NSObject2015-12-23 18:09:42.057 RuntimeTest[1107:123501] rootSuperClass:0x0,Name:nil2015-12-23 18:09:42.057 RuntimeTest[1107:123501] ======================meta class==================2015-12-23 18:09:42.057 RuntimeTest[1107:123501] B metaClass:0x10e503a182015-12-23 18:09:42.057 RuntimeTest[1107:123501] B superMetaClass:0x10e503ab82015-12-23 18:09:42.057 RuntimeTest[1107:123501] A metaClass:0x10e503ab82015-12-23 18:09:42.058 RuntimeTest[1107:123501] A superMetaClass:0x10ec24d502015-12-23 18:09:42.058 RuntimeTest[1107:123501] root metaClass:0x10ec24d502015-12-23 18:09:42.058 RuntimeTest[1107:123501] rootSuperMetaClass:0x10ec24d28,Name:NSObject

从打印结果分析:

RootClass's superClass:0x10ec24d28,Name:NSObject

可看出B类的根类为NSObject

rootSuperClass:0x0,Name:nil

表示了根类的父类为nil

RootClass's superClass:0x10ec24d28,Name:NSObjectrootSuperMetaClass:0x10ec24d28,Name:NSObject

可看出,根元类的父类是他自己的类对象,而他的类对象的父类为nil

这里需要注意:我在一个实例对象b里使用[b class] 可以获取isa所指向的Class类对象B,但是我们在一个Class类对象里调用class方法是无法获取meta-class,它只是返回类而已,如[B class] 返回他自身,而不是B元类

摘录:
http://www.codeceo.com/article/objective-c-runtime-class.html
http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/

0 0
原创粉丝点击