OC基础 - 类对象 | 元类 | 根元类
▶ 什么是对象
OC 中所有对象都是由其所对应的类实例化后得来的!其实类本身也是一种对象,几乎所有类都是 NSObject 的子类
@interface NSObject <NSObject> { Class isa; } @end
Class 是一个结构指针的 typedef 定义
typedef struct objc_class *Class;
objc_class 定义如下:到这里大家可能就晕了,怎么又有一个 isa ?这些 isa 到底是什么?
1 struct objc_class 2 { 3 Class isa; 4 }
其实在 OC 中任何的类定义都是对象,就是说在程序启动的时候任何类定义都对应于一块内存,在编译时编译器会给每一个类生成一个且只生成一个描述其定义的对象,也就是苹果公司说的类对象,它是一个单例
C++ 等语言中所谓的对象,叫做实例对象,对于实例对象我们不难理解,但类对象是干什么的 ?Objective-C 是门动态语言,因此程序里的所有实例对象都是在运行时由运行时库生成的,而类对象就是运行时库用来创建实例对象的依据
那么我们回到之前的问题,为什么这个实例对象的 isa指针 指向的类对象里还有一个 isa 呢 ?这个类对象中的 isa 指向的是元类对象(metaclass_object)
▶ 类对象 | 实例对象
类对象的实质
A. 类对象是由编译器创建的,在编译时所谓的类就是指的它。官方文档中是这样说的: The class object is the compiled version of the class
B. 任何直接或间接继承了 NSObject 的类,它的实例对象中都有一个 isa 指针,指向它的类对象
C. 类对象中存储了关于这个实例对象所属类相关的一切:包括变量、方法、遵守的协议等等,所以类对象才能访问所有关于这个类的信息,并利用这些信息可以产生一个新的实例!注:类对象不能访问任何实例对象的内容
类对象和实例对象的区别
A. 尽管类对象保留了实例对象的原型,但它并不是实例本身:它没有自己的实例变量,也不能执行实例方法,只有实例对象才可以执行实例方法
B. 类的定义也能包含那些特意为类对象准备的类方法!类对象从父类那里继承类方法,就像实例从父类那里继承实例方法一样
类对象与类名
A. 在源代码中,类对象由类名表示,只有在消息表达式中作为接收者时,类名才代表类对象
B. 类对象是由编译器创建的,它缺少自己的数据结构:实例变量
▶ 元类对象
元类对象的实质
A. 类对象其实就是元类对象的一个实例。元类描述了一个类对象,就像类对象描述了实例对象一样。不同的是元类的方法列表是类方法的集合,由类对象的选择器来响应。当向一个类发送消息时 objc_msgSend 会通过类对象的 isa指针 定位到元类,并检查元类的方法列表(包括元类父类)来决定调用哪个方法
B. 元类也是对象,理论上讲它也应该是其他类的实例:实际上元类是根元类(root class’s metaclass)的实例,而根元类是其自身的实例,即根元类的 isa指针 指向自身
super_class | isa
A. 类中的 super_class 指向父类;元类的 super_class 则指向其父类的元类
类的 super_class 和 元类的 super_class 链与链平行,所以类方法的继承与实例方法的继承也是平行的
注:根元类的 super_class 指向自己的根类,这样整个指针链就链接了起来
B. 当一个消息发送给任何一个对象,方法的检查从对象的 isa指针 开始、然后是父类
实例方法在类中定义;类方法在元类和根元类中定义
在一些计算机语言的原理中一个类和元类的层次结构可以更自由地组成,更深的元类链或从单一的元类继承更多的实例化的类
C. 类方法是使用元类的根本原因!苹果在其他方面试图在隐藏元类,例如 [NSObject class] 完全相等于 [NSObject self],所以在形式上它还是返回的 NSObject -> isa 指向的元类
▶ 常用API
以下只做简单了解即可,Runtime 时会详细介绍
// class // 对于 实例对象 返回的是 类 // 对于 类 则不会返回元类,而只会返回 类本身 [@"字符串" class];// 返回的是 __NSCFConstantString [NSString class]; // 返回的是 NSString // object_getClass() // 对于 实例对象 返回的是 类 // 对于 类 返回的则是 元类 // class_isMetaClass() // 是否是元类 //objc_allocateClassPair() // 在运行时创建新的一对儿类和元类 // class_addMethod() // 类中增加方法 // class_addIvar() // 类中增加实例变量 // 两方法需配合使用 objc_registerClassPair!必须先注册,后使用
▶ 结语
类对象和元类对象中当然还会包含一些其他的东西,苹果以后也可能添加其他内容。但对于我们只需要记住:类对象存的是关于实例对象的信息,包括变量、实例方法等;元类对象中存储的是关于类的信息,包括类的版本、名字、类方法等
类对象和元类对象的定义都是 objc_class结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)