iOS底层原理之分类的加载

963 阅读3分钟

前言

我们在上一篇iOS底层原理之类的加载中探索了关于类的加载,在结尾部分我们也注意到了处理分类的代码,这次我们研究下分类的加载。

分类的本质

研究分类的加载,我们先看下分类的本质。

通过源码探究分类本质

我们在源码中搜索category_t,搜索结果如下从上面我们可以得到分类的本质是category_t结构体,结构体里面有namecls实例方法列表类方法列表协议列表属性列表类属性列表元类等信息,其中正因为分类中有属性列表,所以分类才可以动态添加 属性分类只能声明属性,由于没有set、get方法,所以需要动态添加)。

分类的加载

我们以LGPerson为主类,我们添加LGPerson+LGALGPerson+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函数

懒加载类与分懒加载分类混合

从上图中得知懒加载类与分懒加载分类混合时,会迫使主类在编译阶段加载

总结