• Objective-C 对象模型


    Objective-C 是一门面向对象的程序设计语言,它的对象模型是基于类来建立的。我们可以在苹果开源的 runtime(我下载的是当前的最新版本 objc4-646.tar.gz)中发现 Objective-C 对象模型的实现细节。

    对象

    在 Objective-C 中,每一个对象都是某个类的实例,且这个对象的 isa(在 64 位 CPU 下,isa 已经不再是一个简单的指针,在本文中我们暂且把它当作普通指针来理解,后面我会单独写一篇博文来详细介绍 Non-pointer isa )指针指向它所属的类。

    打开刚下载的 runtime 工程,在文件 objc-private.h 的第 127-232 行我们可以找到 Objective-C 中的对象的定义 struct objc_object 。是的,Objective-C 中的对象本质上是结构体对象,其中 isa 是它唯一的私有成员变量。

    Objective-C 对象的定义

    在同一个文件的第 51-52 行我们可以找到 Class 和 id 类型的定义,它们分别是 struct objc_class 和 struct objc_object 类型的指针。这也是为什么 id 类型可以指向任意对象的原因。其中 struct objc_class 就是 Objective-C 中的类的定义,在下一节将会详细介绍。

    1
    2
    
    typedef struct objc_class *Class;
    typedef struct objc_object *id;
    

    对象的类不仅描述了对象的数据:对象占用的内存大小、成员变量的类型和布局等,而且也描述了对象的行为:对象能够响应的消息、实现的实例方法等。因此,当我们调用实例方法 [receiver message] 给一个对象发送消息时,这个对象能否响应这个消息就需要通过 isa 找到它所属的类(当然还有 superclass,本文主要内容不是这个,所以不展开)才能知道。

    打开文件 objc-runtime-new.h ,在第 687-902 行我们可以找到 Objective-C 中的类的定义 struct objc_class 。同样的,Objective-C 中类也是一个结构体对象,并且继承了 struct objc_object 。

    Objective-C 类的定义

    所以,Objective-C 中的类本质上也是对象,我们称之为类对象。按照我们前面所说的所有的对象都是某个类的实例,那么类对象又是什么类的实例呢?答案就是我们将在下一节介绍的元类。

    在 Objective-C 中有一个非常特殊的类 NSObject ,绝大部分的类都继承自它。它是 Objective-C 中的两个根类(rootclass)之一,另外一个是 NSProxy(本文不讨论)。同样的,我们打开文件 NSObject.h ,可以看到 NSObject 类其实就只有一个成员变量 isa ,所有继承自 NSObject 的类也都会有这个成员变量。

    NSObject 类

    元类

    我们上面提到,本质上 Objective-C 中的类也是对象,它也是某个类的实例,这个类我们称之为元类(metaclass)。

    因此,我们也可以通过调用类方法,比如 [NSObject new],给类对象发送消息。同样的,类对象能否响应这个消息也要通过 isa 找到类对象所属的类(元类)才能知道。也就是说,实例方法是保存在类中的,而类方法是保存在元类中的。

    那元类也是对象吗?是的话那它又是什么类的实例呢?是的,没错,元类也是对象(元类对象),元类也是某个类的实例,这个类我们称之为根元类(root metaclass)。不过,有一点比较特殊,那就是所有的元类所属的类都是同一个根元类(当然根元类也是元类,所以它所属的类也是根元类,即它本身)。根元类指的就是根类的元类,具体来说就是根类 NSObject 对应的元类。

    因此,理论上我们也可以给元类发送消息,但是 Objective-C 倾向于隐藏元类,不想让大家知道元类的存在。元类是为了保持 Objective-C 对象模型在设计上的完整性而引入的,比如用来保存类方法等,它主要是用来给编译器使用的。

    说了这么多,大家可能已经有点绕迷糊了,下面我们看一张图,一切自会明了。

    Objective-C 对象模型

  • 相关阅读:
    Duilib 控件类html富文本绘制
    再谈如何使用Taglist?
    如何让vim自动显示函数声明-使用 echofunc.vim插件
    vim 标签页 tabnew 等的操作命令
    php数组操作集锦- 掌握了数组操作, 也就掌握了php
    php字符串操作集锦
    thinkphp疑难解决4
    如何保存gnome的linux的 会话?相当于windows下的休眠?
    开发thinkphp的第一步就是给Application目录(不包括其下的文件)777权限, 关闭selinux
    如何更改gnome-screenshot的默认的保存路径?
  • 原文地址:https://www.cnblogs.com/crash-wu/p/4861620.html
Copyright © 2020-2023  润新知