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;
在这个定义中,下面几个字段是我们感兴趣的
- isa:需要注意的是在Objective-C中,所有的类自身也是一个对象,所以我们也把Class叫类对象,这个对象的Class里面也有一个isa指针,它指向metaClass(元类),我们会在后面介绍它。
- super_class:指向该类的父类,如果该类已经是最顶层的根类(如NSObject或NSProxy),则super_class为nil。
- cache:用于缓存最近使用的方法。一个接收者对象接收到一个消息时,它会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有一部分方法是常用的,很多方法其实很少用或者根本用不上。这种情况下,如果每次消息来时,我们都是methodLists中遍历一遍,性能势必很差。这时,cache就派上用场了。在我们每次调用过一个方法后,这个方法就会被缓存到cache列表中,下次调用的时候runtime就会优先去cache中查找,如果cache没有,才去methodLists中查找方法。这样,对于那些经常用到的方法的调用,但提高了调用的效率。
- 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/
- Objective-C Runtime 总结:类和对象 篇
- Objective-C Runtime总结
- Objective-C Runtime 总结:消息机制 篇
- Objective-C的对象模型和runtime机制
- 【Objective-C Runtime】类和对象的数据结构和消息传递机制
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之一:类与对象
- iOS 添加PCH全局引用文件 —— HERO博客
- Linux命令压缩/优化JPG/PNG图片
- Angular 2的核心概念
- 下载更新App
- ios 手势操作举例
- Objective-C Runtime 总结:类和对象 篇
- Angular 2的变化检测
- hdu1179——二分最大匹配数
- ARM方案公司,三星S5PV210核心板,
- 在CentOS7 上安装mosquitto1.4.1服务器,实现MQTT信息推送功能并增加websocket功能
- swift 学习记录(协议)
- 浅析:手游智能云更新使用方法
- LOAD DATA INFILE 语法
- Angular 2模板语法