readClass 流程
readClass 注释1. 未来类的处理
虽然这个分支里面设置了 ro/rw
,但是正常情况下是不会进来这个分支的,所以可以认定 ro/rw
不是在这里设置的。
- 读取
class
的data()
段,设置ro/rw
- 对新类做重映射
- 使用新类
2. addNamedClass 将类插入gdb_objc_realized_classes总表中
image3. addClassTableEntry 将类插入allocatedClasses类表中
image4. 返回cls
返回结果有以下三种情况
- 原来的类:cls
- 空的类:nil (cls has a missing weak-linked superclass)
- 新的类:something else (space for this class was reserved by a future class)
realizeClassWithoutSwift 流程
【注释以及说明】
- 从命名来看,在swift版本肯定有一个
realizeClassFromSwift
方法 - 在
类cls
上执行首次初始化,包括ro-rw
的数据分配 - 不执行任何
swift端
的初始化 - 返回
类的真实结构
- runtimeLock必须被调用者
写锁定
1. 创建rw,对ro赋值,这里并没有对rw里面的重要参数赋值
image- future 类,第一流程出现过
- normal 类
2. 递归实现supercls和metacls
image 递归出口学习总是环环相扣,Isa走位图中,NSObject的父类指向nil
,在这里验证了
3. 更新父类和元类
image4. 关联这个类到父类的子类列表中
image- 如果有父类,则将cls添加到父类中:
addSubclass(supercls, cls);
- 如果没有,说明本身是根类,则将cls添加到根类列表中:
addRootClass(cls);
5. 附加类别,将ro的内容拷贝到rw
image- 修复cls的方法列表、协议列表和属性列表
- 附上任何未完成的类别
- runtimeLock必须由调用者持有
attachLists 流程
attachLists源码1. 将多个元素的数组添加到多个元素的数组
-
扩容数组
setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
-
将旧数组移到最后
memmove(array()->lists + addedCount, array()->lists, oldCount * sizeof(array()->lists[0]));
-
将新的数组拷贝到前面
memcpy(array()->lists, addedLists, addedCount * sizeof(array()->lists[0]));
2. 将单个元素添加到空数组中
-
直接取第一个元素作为新数组
list = addedLists[0];
3. 将多个元素的数组添加到单个元素的数组
-
扩容数组
setArray((array_t *)malloc(array_t::byteSize(newCount)));
-
把那一个旧的移到末尾
if (oldList) array()->lists[addedCount] = oldList;
-
将新的数组拷贝到前面
memcpy(array()->lists, addedLists, addedCount * sizeof(array()->lists[0]));
-
memcpy 函数
:从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中
4. 除了在加载类的时候会调用:attachLists
还有哪些情况
- 类的加载:处理方法、属性、协议
methodizeClass
- 添加方法:
addMethods
- 添加属性:
_class_addProperty
- 添加协议:
class_addProtocol
- 分类的加载:
attachCategories
补充
元类递归出口条件
元类递归 image- 判断为假
- 初始化一个元类,在表中没有找到,就返回for循环中的内容
ro-rw 相关知识点
imageobjc_registerClassPair
的时候会改变这些标记,这些标记保证 ro
中的数据不会被修改
// cls->ISA()->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);
// cls->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);
- 添加成员变量
class_addIvar
必须放在objc_registerClassPair
将类注册到内存之前
因为成员变量存在ro 的 ivarlist中,类注册到内存中便无法修改了
-
objc_registerClassPair
之后也可以注册属性,因为属性存在rw
的property
列表中 - 如果只添加成员变量,没有添加对应的
setter、getter
方法是不能使用KVC赋值
的。(如果没有 68、69行的代码,第80、81行会报错)
网友评论