oc对象模型理解

来源:互联网 发布:win7无法更改网络位置 编辑:程序博客网 时间:2024/05/21 10:06
首先,OC是一门编程语言,Foundation是一个为OC而生的为了方便程序员使用的编程框架。

这里可以用各司其职来形容它们:
     作为一门面向对象编程语言,OC本身只需要关注自己的对象模型的管理,也就是它只需要管理好OC对象,类,这些东西的组织和联系。
     而作为一个基于OC的框架,Foundation关注的则是让程序员更方便的使用OC语言进行编程。

以上的说明看似是废话,或者说只要是使用OC的程序员都知道的。但是我觉得我没有深刻的理解它,我本身是大三学生,学习的过程中就喜欢深究原理,加上之前鼓捣过半年一年的嵌入式,什么东西都感觉还是弄得清清楚楚,用起来才会踏实,所以翻阅各种帖子研究了一下OC对象模型的实现,在这里总结一下。


从很眼熟的NSString和NSObject开始吧。
     NSString不用说了,字符串类,每天都在用。NSObject这个也熟的不行,我们使用的类基本上都继承自它。然而这里要说的是,严格来说,它们的等级不同,或者说分属不同的范围:NSObject属于OC语言定义的内容,而NSString则是由Foundation框架提供的。
     一个很明显的地方可以看出,NSObject类和我们使用的继承自它的各种类的分别。在Xcode按command + shift + o,分别搜索NSObject.h文件和NSString.h文件可以看到,后者存在于Foundation框架包中,而NSObject.h则user/include下面。
     看一下NSObject的定义可以看到,它本身提供的属性和方法,基本上都是关于对象的分配,初始化,拷贝,内存管理,方法的调用,父类子类的关系等等。

这些就是上面说的,一个编程语言需要操心的点,作为一门面向对象的编程语言,它总要告诉编程者,如何初始化一个对象,如何分配内存,如何拷贝对象等等。OC自己定义了一个根类NSObject,并为根类提供了对象的内存分配,初始化,对象管理,对象模型的实现,使用时只需要继承NSObject类,就可以实现类的定义,对象的初始化,拷贝,销毁,方法调用等功能,这就是OC提供的东西。
     但是OC并不提供字符串的定义,image的定义,文本框的定义,数组和字典等等,这些都是由基于OC的框架提供的,也就是说,OC提供给我们创建,使用,管理类和对象的功能,而字符串,数组这些东西,需要我们使用OC提供的功能来自己实现,Foundation的作用就在此,我们不用再自己写一个继承自NSObject的“string”类,再写一大堆方法来使用字符串,Foundation已经写好了NSString供我们使用,UIKit等其它框架均是如此。

     所以说严格来说,NSObject是OC这门语言提供的类,我们可以继承它来创建自己的类,创建对象,它是一个工具,也是OC这门语言的核心。而对于Foundation可以这么理解:由于编程经常要使用字符串,数组,字典等类型的数据,而OC语言在一开始仅仅提供了NObject这一个根类,每个要使用它的人都需要自己编写继承自它的字符串类和数组类,这非常麻烦并且不合理,所以就有一群人做了这个工作,写好了一大堆常用的类型,每个OC的程序员都使用它来编程,这样就很方便且利于传播了,它就是Foundation。


     讲到这里,就清楚了OC和Foundation的联系,那下面看一下OC的对象模型的实现。

     对于一门面向对象的编程语言,类,对象,方法(也叫函数,OC中叫消息)是核心,OC是怎么组织对象,类,和方法的呢?
     上面说过,每一个类都继承自NSObject类,也就是说,NSObject类如果有成员变量,那么其它的类就都有这个变量,当然是有的,这个成员变量是isa:

     isa的类型是Class,就是说,每一个对象:NSString,NSArray,UILabel等等这些类实例出的变量,里面都包含一个Class类型的isa变量,Class是什么类呢:

     它是一个指针,也就是说isa是一个指向objc_class结构体的指针,即每一个对象中都包含一个objc_class结构体,这个结构体的定义是怎样的呢?

     看到这里可能有点疑惑了,isa本来就是一个指向objc_class的指针,而objc_class结构体中又包含isa指针?很好理解,由于每个对象内部都包含objc_class结构体,所以,这个结构体中的isa指针使用来指向别的对象的,即每个对象都包含一个isa指针,可以用这个指针指向别的对象来建立联系。

     我们知道,使用一个对象的时候,无非就是两点,对象中的实例变量和方法,我们在定义一个类的时候,会定义自己的实例变量和方法,而方法又分为两种,动态方法和静态方法,动态方法是对象方法,静态方法是类方法,那他们分别是怎么联系的呢?
     首先要明确的是,类也是一个对象,对于OC来说一切都是对象,类也有isa指针。
     我们定义了一个新的类,给它添加了一些新的成员变量和类方法,对象方法,然后用这个类实例出了一个对象,我们调用这个对象的对象方法,也可以调用这个类的类方法,然而这个对象在内存中的保存,却只保存了成员变量,并没有保存方法,那对象是怎么执行方法的呢:
     一个对象在内存中的存储可以看成一个结构体,首先,这个结构体中有自己的成员变量,然后还有父类的成员变量,父类的父类的成员变量,这样按照继承链找上去,最终会找到NSObject类,上面说过,NSObject只有一个成员变量就是isa指针,它指向另外一个对象,指向谁呢?对于一个对象来说,它的isa指针,就指向自己的类,比如 NSString *str = [NSString new]; 那这里str对象的isa指针就指向NSString类,当我们向str发送一个对象方法的时候,str就通过自己的isa指针,找到NSString类,再找到这个类中的methodLists,这个列表中就保存了NSString类的所有对象方法,找到并调用就可以了。
     而对于类方法,它是直接被发送给类的,比如[NSString alloc],而NSString类中只保存了对象方法,不保存类方法,这又怎么办呢,前面说过,类也是对象,也有isa指针,那么就通过它的isa指针,找到另外一个类,这个类叫元类<metaclass>,元类保存了类方法列表,找到它就可以调用类方法了。
     元类也是有继承关系的,一子类的元类就继承自父类的元类,当在自己的类中找不到方法时,就向父类寻找,一直找到NSObject,这也就结识了为什么每一个类都可以alloc,new...因为这些是定义在NSObject中的。
     元类也是一个对象,它也有isa指针,所有的元类的isa指针都指向NSObject类的元类,而NSObject元类的isa指针指向自己,下图反映了这个复杂的关系:
     
这样,每个对象在内存中就只保存成员变量和isa指针就可以了,对象方法的实现保存在类中,对象可以通过isa指针调用,类方法保存在元类中,类可以通过isa指针调用,而唯一一个方法实现和自己保存在一起的就是NSObject的元类,它的isa指针指向自己。 
0 0