OC底层探索(十五): 类的加载(三)

2022-05-19  本文已影响0人  ShawnAlex

所用版本:

建议先看下
OC底层探索(十三): 类的加载(一)
OC底层探索(十四): 类的加载(二)

接上次继续看realizeClassWithoutSwift实现类方法

realizeClassWithoutSwift

remapClass

自定义类跟断点走, 可发现先走remapClass

remapClass

对类指针做修正

[ 第一步:生成数据 ]

生成ro数据 data()方法
data()方法

看下内部可看出, data() 内部: bits & FAST_DATA_MASK 与操作拿到data(), 而这里的data()是个地址指针 class_rw_t *类型, 获取之后外层再强制转成class_ro_t *指针。
留意下, 几乎所有引用到class_ro_t的地方都会使用了const关键字做修饰, 苹果希望ro像是一个静态, 不愿意被外界随意修改的属性, 而rw无.

关于那个强转稍微说下, class_rw_tclass_ro_t2个结构体虽然有点差距, 但是ro需要的部分rw都可以找到, 可以说是一一给赋值关系。

举个例子: 设置一个Method方法

Method

其中class_getInstanceMethod返回是一个Method *类型

Method class_getInstanceMethod(Class cls, SEL sel)

OK没问题, 那么我们只用 Methodmethod_name, method_imp写成一个新的结构体

objc_method

发现也是正常运行, 通过打印信息可发现, 只有2个成员。这个是就跟class_rw_t *强转class_ro_t *一样, 只取对应信息强转调用。但是也要留意两者是格式对应或包含关系, 如果格式地址无法解析或者不匹配到位, 会发生解析不出来情况。

生成rw数据

继续往下走, 可发现

[ 第二步:完善父类链元类链 ]

完善父类链元类链 完善类
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \
      uintptr_t nonpointer        : 1;                                       \
      uintptr_t has_assoc         : 1;                                       \
      uintptr_t has_cxx_dtor      : 1;                                       \
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;                                       \
      uintptr_t weakly_referenced : 1;                                       \
      uintptr_t deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)

其中 nonpointer:表示是否对isa指针开启优化。0:纯isa指针,1:不只是类对象地址,isa中包含了类信息、对象的引用计数等。其中大部分的类都是nonpointer类,元类不是nonpointer

接下来是对几种特殊情况的纯指针处理

特殊情况的纯指针
isa关系

也都要, 要将isa改变成raw isa

关联父类, 元类 调整父类ro

如果是父类需要更多的内存空间, 会做个ro做调整

reconcileInstanceVariables reconcileInstanceVariables gdb_objc_class_changed

找最大的实例变量做个重新对齐, 并与父类ro作比较, 如果没超出范围直接返回, 超出就重新设置ro

举个例子: 父类SRTest, 子类SRTestSub, 父类里面2个NSString *, 子类什么也没有

例子
运行一下
例子

有点父欠子还那味儿了, 回到realizeClassWithoutSwift 继续看

setInstanceSize setInstanceSize

ro计算内存大小存到缓存中, 下次就从缓存中取

处理标识

处理一些Flag标志位

子类关联

父类子类进行关联

addSubclass

...不得不说, 父亲管的是真严格啊 :), 根类是单独设置的, 也稍微看一下

addRootClass
/***********************************************************************
* _firstRealizedClass
* The root of all realized classes
**********************************************************************/
static Class _firstRealizedClass = nil;

相邻为设置为nil, 自己设置为NSObject

[ 第三步:methodizeClass ]

继续往下走可看到进行走方法methodizeClass

methodizeClass

methodizeClass 主要从ro中读取方法列表(包括分类中的方法), 属性列表, 协议列表等 赋值给rw,并返回cls。 看下内部

methodizeClass 方法/属性/协议获取 根元类

再往下看都是分类加载内容, 放在下一篇: OC底层探索(十六): 类的加载(四)

上一篇 下一篇

猜你喜欢

热点阅读