iOS 底层探索篇 ——类的加载原理(中)

iOS 底层探索篇 ——类的加载原理(中)

_read_images流程分析ro,rw

上回说到readClass 里面给类加上了名字,那么rorw是在哪里加的呢?回到_read_images打上断点一点一点探究。
remap classes 这里打上断点后运行,发现没有进去。
在这里插入图片描述

懒加载和非懒加载

为了节约内存和速度,苹果不会把所有的类都加载,而是把我们自己的类以一种懒加载的形式按需加载,当实现load之后,就是非懒加载的形式了。而如果没有实现load,就是懒加载类,当类第一次收到消息的时候,就会被加载。

懒加载类情况:数据加载推迟到第一次消息的时候

  • lookUpImpOrForward
  • realizeClassMaybeSwiftMaybeRelock
  • realizeClassWithoutSwift
  • methodizeClass

非懒加载类情况:map_images的时候 加载所有类数据

  • _getObjc2NonlazyClassList
  • readClass
  • realizeClassWithoutSwift
  • methodizeClass

往下走,看到objc_msgSend_fixup,和类无关就跳过不看。继续往下走discover protocols也和类无关不看。在往下看到protocol references,也和类无关,继续往下走。discover categories,分类,继续跳过。继续往下走看到realize non-lazy classes,这个是非懒加载类的实现,和类的实现有关,接下来就研究这里。

因为要研究自己的类,所以需要把实现类的load方法,否则LGPerson就无法进入这里。

添加load方法后运行,发现是从read_images的时候进来的。
在这里插入图片描述

注释掉load 方法后运行,发现在realizeClassWithoutSwift有实现LGPerson,打印一下发现确实是在收到消息的时候调用的。
在这里插入图片描述
在这里插入图片描述

之后就开始研究了。加入方法确认是我们要研究的类后,运行程序。
在这里插入图片描述
运行后发现的确进来了。
在这里插入图片描述
往下走,发现调用了realizeClassWithoutSwift
在这里插入图片描述
进去后输出一下cls,发现是LGPerson
在这里插入图片描述
继续往下走
在这里插入图片描述
然后输出po,看到这里打出ro的baseMethodList,这说明了方法等数据都已经加载进来。
在这里插入图片描述

在这里插入图片描述
往下走去找哪里进行了赋值。发现进入了这里,而ro,rw也是在这里设置。而看到rw->set_ro(ro),这也是为什么rw的数据和ro是相似的,除非是动态处理的地方,比如addMethodaddProtocols
在这里插入图片描述
往下走看到这里如果是元类的话,就会进行rawIsa的处理,所以这也是为什么元类的isa是纯isa的原因。
在这里插入图片描述
往下看,看到这里如果设置了DisableNonpointerIsatrue,就会设instancesRequireRawIsatrue,然后调用setInstancesRequireRawIsaRecursively。这也是为什么设置环境变量DisableNonpointerIsa为YES的时候,会得到纯isa的原因。
在这里插入图片描述
继续往下走,看到这里设置了父类和isa
在这里插入图片描述
在往下看到在这里设置了子类。
在这里插入图片描述
在下面设置一个条件来确定是LGPerson类,并加上一个条件判断不是元类以免元类进来。
在这里插入图片描述
运行后发现robaseMethodList还是没有内容
在这里插入图片描述
接下来就进入methodizeClass里面查看。
在这里插入图片描述

把之前的条件复制进来,打下断点后运行。
在这里插入图片描述

继续往下走,看到这里获取了robaseMethods
在这里插入图片描述
往下走一行,等赋值后查看list,发现是有地址的,尝试打印,发现和之前的打印出来的没有什么区别。
在这里插入图片描述
在这里插入图片描述

继续往下走,去到prepareMethodLists里面,在里面打下断点
在这里插入图片描述
继续运行后,发现进入到了fixupMethodList里面。
在这里插入图片描述
进入后看到有setName的操作,而name的值则是selsel_cname是将sel转为const char *类型的值。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
继续往下看,看到这个地址还会根据sel的地址来进行排序。不要尝试去改小地址的位置,因为小地址排完序后不可变。也不要去改变不是标准大小的大列表的顺序,因为stable_sort无法正确拷贝入口。
在这里插入图片描述
那么是否有排序了呢,在排序前后打印出sel来查看是否排序
在这里插入图片描述
运行时一定要确认是LGPerson类进来的,然后在研究。发现确实对方法进行了排序。
在这里插入图片描述
接着回到methodizeClass,看看ro里的baseMethods是否有值。发现这里有值了,但是这里的顺序不一样了,可以注意到分类的saysomething和主类的saysomething放在一起了,而且分类的就在主类的前面,这也解释了为什么方法查找中为什么method–就是调用分类的同名方法。这里也说明了prepareMethodLists里面进行了方法的排序等工作。
在这里插入图片描述

之前看到methodizeClass的注释写着Attach categories(链接分类),那么分类在这里会怎么处理呢?探索之前,先来了解什么是分类。
在这里插入图片描述

分类

要研究分类,就先clang一下看一下c啪啪文件。生成cpp文件后打开,在最后一行看到了_category_t就有了我们的LG分类,
在这里插入图片描述
来查找一下_category_t是什么东西,发现也是一个结构体。这里为什么有instance_methodsclass_methods,而不直接写一个methodLIst之类的东西呢?这是因为分类没有元类,所以方法都写在这里面,所以需要分开写。
在这里插入图片描述
往下看,看到这里写了个LGPerson。在静态编译的时候,还没跑起来运行时,名字不知道是什么,所以写了个LGPerson上去。而下面的0代表没有protocol。
在这里插入图片描述

添加一个协议然后重新clang一下再来看。发现下面就不为0了。
在这里插入图片描述
往下看,分类里的方法都看到了,但是确没有set和get方法。
在这里插入图片描述
在回到源码里查看category_t,看看是否和cpp里面的一样。发现多了个_classProperties,但是注释写着他不是一直都有的。
在这里插入图片描述
那么分类是如何如何写到类中的呢?且听下回分解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值