runtime.h
1.数据类型定义
1.1 方法Method
|
|
如上所述,Method即为method_t的结构体实例指针,其组成包含SEL选择器、IMP函数指针和方法类型描述。
1.2 变量Ivar
|
|
Ivar为ivar_t的结构体实例指针,组成主要包括变量名,变量类型和偏移量(用于内存布局)。
1.3 分类Category
|
|
Category为category_t的结构体实例指针,内部主要包括**分类名、所属类、实例方法列表指针、类方法列表指针和协议列表指针。
1.4 属性objc_property_t
|
|
指向property_t结构体实例的指针,内部包含名称和支持的特性。
1.5 类Class
|
|
- Class即为指向objc_class结构体实例的指针。Class内部包含Class类型的isa指针。
- 由于Class的结构与id一致,均只包含isa的Class指针,故Class也是对象(面向对象中一切皆为对象)。
- Class中的isa指向的是metaclass。
2.方法定义
2.1 使用对象的相关方法
2.1.1 获取对象所属类
|
|
2.1.2 给对象设置所属类
|
|
返回值为设置之前的类
2.1.3 判断执行对象是否为类
|
|
返回YES,则传入对象为Class或metaclass(印证了Class也是对象)。
2.1.4 获取对象的实例变量的值
|
|
2.1.5 向对象的实例变量设置值
|
|
对于实例变量Ivar来说,
- 若其内存管理方式已知(如在ARC环境下),就会直接按照其进行设置;
- 若未知,则按照__unsafe_unretained方式进行设置;
|
|
对于实例变量Ivar来说,
- 若其内存管理方式已知(如在ARC环境下),就会直接按照其进行设置;
- 若未知,则按照__strong方式进行设置;
2.2 获取类定义的相关方法
2.2.1 根据名字获取类
|
|
- 所有方式,均可以查询到是否存在改类。
- 区别:当Class没有注册到运行时系统中时,objc_getClass方法会在类的处理回调执行后,再次查询该类是否已存在;objc_lookUpClass则不会;objc_getRequiredClass则会自动终止进程(只会查询编译时已确定的Class)。
2.2.2 获取类的原类
|
|
类方法都是保存在metaclass中的。
2.2.3 获取所有的类定义
|
|
注意:
不要假定返回的所有类都继承自NSObject,故对其中的类调用方法时需要提前检查该方法是否已经实现。
|
|
我们一般使用此版本,不过使用完的列表对象,需要手动释放内存。
2.3 使用类的相关方法
2.3.1 获取类的名字
|
|
2.3.2 判断类是否为原类(metaclass)
|
|
2.3.3 获取类的父类
|
|
2.3.4 返回类的实例的大小(OC对象的大小)
|
|
2.3.5 获取类中的实例变量
|
|
返回的是指定名字的实例变量对象(非属性对象),类型为Ivar,即ivar返回的是指定名字的实例变量对象(非属性对象),类型为Ivar,即ivar返回构体指针。
2.3.6 获取类中的类变量
|
|
一般来说,Class中并没有所谓的“类变量”。我们可以使用此方法来返回“isa”指针的对象。
2.3.7 拷贝并返回类的实例变量列表
|
|
- 返回的是包含所有实例变量Ivar指针的数组,使用完毕后需要手动释放内存;
- 只有自身类的实例变量,不包括父类
2.3.8 获取指定类的实例方法对象
|
|
注意:此方法会查找父类中的实现。
2.3.9 获取指定类的类方法对象
|
|
注意:此方法会查找父类中的实现。
2.3.10 获取指定类中的指定方法实现
|
|
注意,返回的IMP为运行时中的内部对象,并非真正的函数指针。当找不到方法实现时,返回的是消息转发机制中的函数指针。
2.3.11 拷贝并返回类中的方法列表
|
|
- 返回的是包含所有方法Method指针的数组,使用完毕后需要手动释放内存;
- 只有自身类的方法,不包括父类
2.3.12 拷贝并返回类遵循的协议列表
|
|
这里的Protocol实质上是NSObject的子类。
2.3.13 获取类的属性对象(property)
|
|
2.3.14 拷贝并返回类的属性列表
|
|
- 返回的是包含所有属性objc_property_t指针的数组,使用完毕后需要手动释放内存;
- 只有自身类的属性,不包括父类
2.3.15 获取类的实例变量布局
|
|
得到的是类的实例变量的布局描述,这里留下疑问???
2.3.16 获取类的weak的实例变量布局
|
|
第二个疑问???
2.3.17 给类添加新方法
|
|
- 可以向类中动态添加方法
- 可以覆盖父类的同名方法
- 不会替换本类中已存在方法的实现(修改方法实现,可使用method_setImplementation方法)
2.3.18 替换类中指定方法的实现
|
|
- 若方法不存在,则向该类中自动添加方法;
- 方法已存在,则替换方法实现
2.3.19 向类中添加实例变量
|
|
- 只能在objc_allocateClassPair之后(动态创建类)并在objc_registerClassPair(向运行时系统注册类)之前调用,将实例变量添加到类布局中;
- 只能添加到本类中,不能添加到metaclass中;
- alignment对齐方式,最少为“1<<alignment”;对于指针类型变量,传入log2(sizeof(pointer_type))。
2.3.20 向类中新增遵循的协议
|
|
返回NO时,即该类已遵循该协议
2.3.21 向类中新增属性
|
|
2.3.22 替换类中的指定属性
|
|
2.3.23 向类中设置实例变量布局
|
|
???
2.3.24 向类中设置weak的实例变量布局
|
|
???
2.4 类实例化的相关方法
2.4.1 创建类的实例
|
|
2.5 动态添加类的相关方法
2.5.1 创建类及对应的元类
|
|
在运行时向系统添加类,需要先调用此方法(默认创建了类及对应的元类),之后可以使用class_addMethod和class_addIvar等添加方法和实例变量;最后调用objc_registerClassPair将该类注册到runtime系统中(实例方法需添加到本类,类方法添加到对应的元类中)。
2.5.2 注册新创建的类
|
|
2.5.3 释放类及元类
|
|
注意:若存在本类的子类,不要调用此方法。
2.6 使用方法(Method)的相关方法
2.6.1 获取方法中的选择器SEL
|
|
2.6.2 获取方法的实现IMP
|
|
2.6.3 获取方法的类型编码
|
|
2.6.4 获取方法的参数个数
|
|
2.6.5 拷贝并返回方法的返回类型
|
|
需要手动释放返回值。
2.6.6 拷贝并返回方法的参数类型
|
|
需要手动释放返回值。
2.6.7 获取方法的描述结构体信息
|
|
2.6.8 设置方法实现
|
|
返回值为先前的实现。
2.6.9 交换两个方法的实现
|
|
2.7 使用实例变量的相关方法
2.7.1 获取实例变量的名称
|
|
2.7.2 获取实例变量的类型编码
|
|
2.7.3 获取实例变量的偏移量
|
|
2.7 使用属性的相关方法
2.7.1 获取属性名称
|
|
2.7.2 获取属性特性描述
|
|
2.7.3 拷贝并返回属性的特性列表
|
|
返回的属性列表数组需要手动释放。
2.7.4 拷贝并返回属性特性的值
|
|
返回值需要手动释放。
2.8 选择器相关方法
2.8.1 获取选择器的名称
|
|
2.8.2 向运行时系统注册选择器
|
|
- 在向类定义中添加方法前,需要保证方法对应的SEL已注册到运行时系统中;
- 若同名SEL已注册,则直接返回
2.8.3 判断两个SEL是否相同
|
|
与“==”等价。
2.9 关联对象相关
2.9.1 关联规则
|
|
2.9.2 设置对象的关联对象
|
|
2.9.3 获取对象的关联对象值
|
|
2.9.4 移除对象的所有关联对象
|
|
3.类型编码的相关定义
3.1 OC类型编码
编码 | 意义 |
---|---|
c | char |
i | int |
s | short |
l | long |
q | long long |
C | unsigned char |
I | unsigned int |
S | unsigned short |
L | unsigned long |
Q | unsigned long long |
f | float |
d | double |
B | C++ bool 或 C99 _Bool |
v | void |
* | 字符指针(C字符串) |
@ | id或OC类的对象 |
# | 类对象(Class) |
: | 选择器(SEL) |
[array type] | 数组 |
{name=type…} | 结构体 |
(name=type…) | 联合体 |
^type | c指针 |
? | 未知(可用于函数指针) |
3.2 OC方法编码
编码 | 意义 |
---|---|
r | const |