美文网首页
category底层原理

category底层原理

作者: Q妹_ | 来源:发表于2019-12-11 17:59 被阅读0次

    category原码

    struct _category_t {
        const char *name;
        struct _class_t *cls;
        const struct _method_list_t *instance_methods;
        const struct _method_list_t *class_methods;
        const struct _protocol_list_t *protocols;
        const struct _prop_list_t *properties;
    };
    

    通过查看源码可以看出,给分类可以添加实例方法,类方法,协议,属性(无法添加实例变量)。

    添加分类NSPerson+Add类

    
    #import "NSPerson.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface NSPerson (Add)
    @property (nonatomic,strong)NSString *testStr;
    - (void)add;
    + (void)testAdd;
    @end
    
    #import "NSPerson+Add.h"
    
    @implementation NSPerson (Add)
    
    - (void)add{
    }
    + (void)testAdd{
     }
    
    @end
    

    使用clang查看编译源码

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc NSPerson+Add.m

    //NSPerson 结构体
    struct _category_t {
        const char *name;
        struct _class_t *cls;
        const struct _method_list_t *instance_methods;
        const struct _method_list_t *class_methods;
        const struct _protocol_list_t *protocols;
        const struct _prop_list_t *properties;
    };
    extern "C" __declspec(dllimport) struct objc_cache _objc_empty_cache;
    #pragma warning(disable:4273)
    
    //分类添加的实例方法列表
    static struct /*_method_list_t*/ {
        unsigned int entsize;  // sizeof(struct _objc_method)
        unsigned int method_count;
        struct _objc_method method_list[1];
    } _OBJC_$_CATEGORY_INSTANCE_METHODS_NSPeson_$_Add __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_objc_method),
        1,
        {{(struct objc_selector *)"add", "v16@0:8", (void *)_I_NSPeson_Add_add}}
    };
    
    //分类添加的类方法列表
    static struct /*_method_list_t*/ {
        unsigned int entsize;  // sizeof(struct _objc_method)
        unsigned int method_count;
        struct _objc_method method_list[1];
    } _OBJC_$_CATEGORY_CLASS_METHODS_NSPeson_$_Add __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_objc_method),
        1,
    //方法名字
        {{(struct objc_selector *)"testAdd", "v16@0:8", (void *)_C_NSPeson_Add_testAdd}}
    };
    
    //添加的属性列表
    static struct /*_prop_list_t*/ {
        unsigned int entsize;  // sizeof(struct _prop_t)
        unsigned int count_of_properties;
        struct _prop_t prop_list[1];
    } _OBJC_$_PROP_LIST_NSPeson_$_Add __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_prop_t),
        1,
    //testStr属性名字
        {{"testStr","T@\"NSString\",&,N"}}
    };
    
    extern "C" __declspec(dllimport) struct _class_t OBJC_CLASS_$_NSPeson;
    
    
    // *********NSPerson+Add的结构体*************
    static struct _category_t _OBJC_$_CATEGORY_NSPeson_$_Add __attribute__ ((used, section ("__DATA,__objc_const"))) = 
    {
        "NSPeson",//name
        0, // &OBJC_CLASS_$_NSPeson,
    //实例方法列表
        (const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_NSPeson_$_Add,
    //类方法列表
        (const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_NSPeson_$_Add,
        0,
    //属性列表
        (const struct _prop_list_t *)&_OBJC_$_PROP_LIST_NSPeson_$_Add,
    };
    static void OBJC_CATEGORY_SETUP_$_NSPeson_$_Add(void ) {
        _OBJC_$_CATEGORY_NSPeson_$_Add.cls = &OBJC_CLASS_$_NSPeson;
    }
    #pragma section(".objc_inithooks$B", long, read, write)
    __declspec(allocate(".objc_inithooks$B")) static void *OBJC_CATEGORY_SETUP[] = {
        (void *)&OBJC_CATEGORY_SETUP_$_NSPeson_$_Add,
    };
    static struct _category_t *L_OBJC_LABEL_CATEGORY_$ [1] __attribute__((used, section ("__DATA, __objc_catlist,regular,no_dead_strip")))= {
        &_OBJC_$_CATEGORY_NSPeson_$_Add,
    };
    static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
    

    通过编译器生成的实例方法列表,类方法列表和属性列表都对应的赋值给添加的分类的结构体中,可以看出在编译时期,分类添加的方法和属性是放到分类本身的结构体中

    
    // *********NSPerson+Add的结构体*************
    static struct _category_t _OBJC_$_CATEGORY_NSPeson_$_Add __attribute__ ((used, section ("__DATA,__objc_const"))) = 
    {
        "NSPeson",//name
        0, // &OBJC_CLASS_$_NSPeson,
    //实例方法列表
        (const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_NSPeson_$_Add,
    //类方法列表
        (const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_NSPeson_$_Add,
        0,
    //属性列表
        (const struct _prop_list_t *)&_OBJC_$_PROP_LIST_NSPeson_$_Add,
    };
    

    为什么分类的方法会覆盖类的方法?
    在runtime运行时,会先遍历找出所有的分类,然后在将原来的类的方法添加新的方法列表中,然后根据分类的数据扩容,在将分类的方法添加到类的类对象或元类的方法中时,使用将原来类的方法向后移,这样的话分类的方法在原来类的方法的前面,所以会覆盖到原来的类方法,(注并不真正的覆盖,而且分类的方法调用顺序靠前,在找到方法后,就不会在继续往下找)

    后编译的分类,先调用

    Category和Class Extension的区别是什么?
    Class Extension在编译的时候,它的数据就已经包含在类信息中
    Category是在运行时,才会将数据合并到类信息中

    相关文章

      网友评论

          本文标题:category底层原理

          本文链接:https://www.haomeiwen.com/subject/pkplgctx.html