文章目录
- [iOS - Runtime - Class的结构](#iOS - Runtime - Class的结构)
-
- 前言
- [1. Class的结构](#1. Class的结构)
-
- [1.1 Class的结构](#1.1 Class的结构)
-
- [1.1.1 objc_class](#1.1.1 objc_class)
- [1.1.2 class_rw_t](#1.1.2 class_rw_t)
- [1.1.3 class_ro_t](#1.1.3 class_ro_t)
- [1.2 class_rw_t和class_ro_t的区别](#1.2 class_rw_t和class_ro_t的区别)
- [1.3 class_rw_t和class_ro_t的关系](#1.3 class_rw_t和class_ro_t的关系)
-
- [1.3.1 分析关系](#1.3.1 分析关系)
- [1.3.2 原因](#1.3.2 原因)
- [1.4 method_t](#1.4 method_t)
-
- [1.4.1 Type Encoding](#1.4.1 Type Encoding)
- [1.4.2 types说明](#1.4.2 types说明)
-
- [1.4.2.1 - (void)test](#1.4.2.1 - (void)test)
- [1.4.2.2 - (void)test:(NSString *)name](#1.4.2.2 - (void)test:(NSString *)name)
iOS - Runtime - Class的结构
前言
1. Class的结构
前面我们学习OC对象的时候,了解了class类对象、meta-class元类对象

实际上,class类对象、meta-class元类对象底层结构体都是class,元类对象可以认为是特殊的类对象。他们底层结构是一样的,只不过存储的内容有所区别
1.1 Class的结构
Class的结构如下图所示:

1.1.1 objc_class

里面存储了
isasuperclasscachebits
其中的bits,& FAST_DATA_MASK位运算之后,拿到class_rw_t,class_rw_t里面的ro则是class_ro_t
1.1.2 class_rw_t
class_rw_t里面的methods、properties、protocols是二维数组,是可读可写的,包含了类的初始内容、分类的内容

1.1.3 class_ro_t
class_ro_t里面的baseMethodList、baseProtocols、ivars、baseProperties是一维数组,是只读的,包含了类的初始内容

1.2 class_rw_t和class_ro_t的区别
对于他们里面的主要内容:
class_rw_t:methods、properties、protocolsclass_ro_t:baseMethodList、baseProtocols、ivars、baseProperties
区别主要是:
class_rw_t的主要成员是二维数组,class_ro_t的主要成员是一维数组class_rw_t的主要成员是可读可写的,class_ro_t是只读的
1.3 class_rw_t和class_ro_t的关系
class_rw_t和class_ro_t里面的结构很像,但是class_ro_t的成员基本上带了base。
1.3.1 分析关系
其实刚开始的时候不存在rw的,class里面的东西都保存在ro里面,bits取出来的其实是ro,rw是后面才生成的
因为rw是可读可写的,生成的时候,会把ro里面的东西合并进去,然后把rw设置为datacls->setData(rw),此时rw就替换了原本ro的位置,同时rw把ro属性指向原来的ro对象
1.3.2 原因
class_rw_t里面的数据基本上是二维数组,并且是可读可写。
我们知道分类的东西是runtime阶段才附加进去的,在将分类的东西合并到class里面的时候。
因此他们之间是相互配合的,class_ro_t先是存储了编译期间固定的东西,运行时一些动态的东西则是存入class_rw_t,class_rw_t在初始化前会将class_ro_t的东西先附加进去。于是class_rw_t里面就有完整的东西
1.4 method_t
method_t是对方法\函数的封装

IMP代表函数的具体实现

SEL代表方法\函数名,一般叫做选择器,底层结构跟char *类似- 可以通过
@selector()和sel_registerName()获得 - 可以通过
sel_getName()和NSStringFromSelector()转成字符串 不同类中相同名字的方法,所对应的方法选择器是相同的
- 可以通过

- types包含了函数返回值、参数编码的字符串
| 返回值 | 参数1 | 参数2 | ... | 参数n |
|---|
1.4.1 Type Encoding
iOS中提供了一个叫做@encode的指令,可以将具体的类型表示成字符串编码


1.4.2 types说明

使用Xcode 12.5.1 iPhone(12.4)模拟器
1.4.2.1 - (void)test
方法- (void)test;对应的types是v16@0:8
- (void)test;实际上C语言函数为:- (void)test:(id)self _cmd:(SEL)_cmd,包含self、_cmd两个参数
于是types表示如下表:
| v | 16 | @ | 0 | : | 8 |
|---|---|---|---|---|---|
void 无返回值 |
2个参数共16字节 |
第1个参数:id类型 |
第1个参数:从0字节开始 |
第2个参数:SEL类型 |
第2个参数:从8字节开始 |
1.4.2.2 - (void)test:(NSString *)name
给test方法增加一个name参数,此时types是v24@0:8@16
types表示如下表:
于是types表示如下表:
| v | 24 | @ | 0 | : | 8 | @ | 16 |
|---|---|---|---|---|---|---|---|
void 无返回值 |
3个参数共24字节 |
第1个参数:id类型 |
第1个参数:从0字节开始 |
第2个参数:SEL类型 |
第2个参数:从8字节开始 |
第3个参数:id类型 |
第3个参数:从16字节开始 |
@oubijiexi