前言
我们在上一篇iOS底层原理之类的加载中探索了关于类的加载,在结尾部分我们也注意到了处理分类的代码,这次我们研究下分类的加载。
分类的本质
研究分类的加载,我们先看下分类的本质。
通过源码探究分类本质
我们在源码中搜索category_t,搜索结果如下从上面我们可以得到分类的本质是
category_t结构体,结构体里面有name、cls、实例方法列表、类方法列表、协议列表、属性列表、类属性列表、元类等信息,其中正因为分类中有属性列表,所以分类才可以动态添加 属性(分类只能声明属性,由于没有set、get方法,所以需要动态添加)。
分类的加载
我们以LGPerson为主类,我们添加LGPerson+LGA和LGPerson+LGB两个分类。
我们从上一篇类的加载中得知最终会通过realizeClassWithoutSwift函数将类的信息关联起来,而realizeClassWithoutSwift函数通过methodizeClass函数来处理分类。
methodizeClass函数分析
从
methodizeClass函数中我们可以看到最终是通过attachToClass函数来将分类添加到主类上的。
attachToClass函数
我们查看attachToClass函数代码从中可以看到
attachToClass函数最终又调用了
attachCategories函数
attachCategories函数
这个函数里面处理了分类的方法、属性、协议等。
分类加载反推路径分析
- 我们将断点打在
attachCategories函数中的LGPerson判断部分,运行代码到断点位置,打印堆栈信息通过上图我们可以发现实际上
分类加载反推路径为attachCategoriyes->load_categories_nolock(执行两次) ->loadAllCategories->load_images
分类加载正反推路径总结
主类分类混合加载
主类跟分类混合加载主要区分在是否是懒加载类,即是否实现了+load函数
懒加载类与懒加载分类混合
我们在main函数中打下断点,如图所示我们发现此时仅仅执行了
readClsss函数,通过我们前面dyld与objc的关联我们知道,这个readClass函数在编译阶段就会执行,因此得知此时并没有加载类和其分类。我们继续执行代码到NSLog处,此时我们发现已经加载了
类和其分类,因此我们可以总结出来:懒加载类与懒加载分类混合,加载实际推迟到第一次消息转发时,即本文中的[LGPerson alloc]时
非懒加载类与懒加载分类混合
还是同懒加载类与懒加载分类混合分析相同,从图中我们发现还有执行
[LGPerson alloc]时,类已经被加载了,即在编译阶段就已经被加载了
非懒加载类与非懒加载分类混合
从上图中我们得知也是在
编译阶段加载了,只是在attachToClass函数中执行了两次load_categories_nolock函数
懒加载类与分懒加载分类混合
从上图中得知
懒加载类与分懒加载分类混合时,会迫使主类在编译阶段加载