Category与+load、+initialize方法

2020-01-03  本文已影响0人  丶月月鸟

Catergory

在编译时,会将分类生成一个category_t结构体

category_t结构体

分类的本质:runtime会将分类中的方法、协议、属性分别拼接成3个数组,且分类方法、协议、属性的顺序和分类的编译顺序有关,后编译的会在前面。然后回将生成的数组进行momerymove(内存移动)操作,拼接在类对象和元类对象的rw->method_list等属性的最前面

分类源码调用顺序:

在pobjc-os.mm文件中

_objc_init 

map_images

map_images_nolock

在pobjc-runtime-new.mm 文件中

_read_images

remethodizeClass

attachCategories

attachLists

realloc、memmove、 memcpy


+load方法

调用时机:会在runtime加载类和分类时调用,且只调用一次。

调用顺序:分类的+ load方法和类的 + load方法都会调用,且一定是原类中的load方法先调用,因为在源码中,会先找到原类中的+ load方法的内存地址,直接单独调用,再按照分类文件的编译顺序进行分别调用分类中的+ load方法,先编译的先调用。

源码调用顺序: 

+load方法调用过程

+initialize方法

调用时机:+initialize方法,是在类第一次调用objc_msgSend方法前调用,即类第一次接收到消息前调用

调用顺序:+initialize方法在源码中,先判断当前类是否调用过+initialize(initialized);如果没有调用过,则会通过递归的方法寻找其父类的+initialize方法;接下来会判断当前父类是否initialized,如果父类没有调用过则父类先调用callInitialize即调用+initialize方法,再进行调用子类的+initialize方法。

源码调用顺序:

在pobjc-msg-arm64.s文件中

objc_msgSend

在pobjc-runtime-new.mm文件中

class_getInstanceMethod

lookUpImpOrNil

lookUpImpOrForward

_class_initialize

callInitialize

objc_msgSend(cls, SEL_initialize)

区别:

1)+initialize方法是通过objc_msgSend方法调用,与load方法的直接通过地址指针进行调用不同

2)如果子类没有调用+initialize方法,且子类不存在+initialize方法,则会调用父类的+initialize方法,因此父类的+initialize方法有可能会调用多次

3)因为+initialize方法是通过objc_msgSend方法调用,因此分类的+initialize方法会覆盖本身的+initialize方法

上一篇下一篇

猜你喜欢

热点阅读