美文网首页
在iOS中分类和类中添加属性和方法的区别

在iOS中分类和类中添加属性和方法的区别

作者: 南风_001 | 来源:发表于2019-08-14 16:00 被阅读0次

    分类和类都可以添加方法和属性

    • 属性
      分类通过runtime添加属性
      类直接添加
    • 方法
      添加方式一样

    生成

    类中生成的有: 成员变量_ivar_list_t 属性变量:_prop_list_t 方法:_method_list_t(setter 和getter)

    这里给出TestExpand 以及他的两个分类TestExpand+test TestExpand+Additions

    TestExpand  
    TestExpand+test
    TestExpand+Additions
    

    其中TestExpand 有属性以及方法
    TestExpand.h

    @interface TestExpand : NSObject
    
    @property(nonatomic, copy) NSString *mustProperty;
    
    - (void)testExpanded;
    
    @end
    

    TestExpand.m

    - (void)setMustProperty:(NSString *)mustProperty {
        NSLog(@"这是类自己的===mustProperty");
        mustProperty = mustProperty;
    }
    - (NSString *)mustProperty {
        NSLog(@"这是类自己的");
        return _mustProperty;
    }
    - (void)testExpanded {
        NSLog(@"这是类里面的=======testExpanded");
    }
    

    TestExpand+test和TestExpand+Additions有属性和方法

    TestExpand+Additions.h

    @interface TestExpand (Additions)
    
    @property(nonatomic, copy) NSString *mustProperty;
    
    - (void)testExpanded;
    @end
    

    TestExpand+Additions.m

    #import "TestExpand+Additions.h"
    #import<objc/runtime.h>
    static const char * thisisname = "thisisname";
    @implementation TestExpand (Additions)
    // 使用runtime来给分类添加属性
    - (void)setMustProperty:(NSString *)mustProperty {
        NSLog(@"这是延展里面的mustProperty");
    
        objc_setAssociatedObject(self, thisisname, mustProperty, OBJC_ASSOCIATION_COPY);
    }
    
    - (NSString *)mustProperty {
        NSLog(@"这是延展里面的");
        return objc_getAssociatedObject(self, thisisname);
    }
    - (void)testExpanded {
        NSLog(@"这是延展里面的=======testExpanded");
    }
    @end
    
    

    下比较的是分类和类添加属性之后有什么不同。

    extern "C" unsigned long OBJC_IVAR_$_TestExpand$_mustProperty;
    struct TestExpand_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
        NSString * _Nonnull _mustProperty;
    };
    //_ivar_list_t
    static struct /*_ivar_list_t*/ {
        unsigned int entsize;  // sizeof(struct _prop_t)
        unsigned int count;
        struct _ivar_t ivar_list[1];
    } _OBJC_$_INSTANCE_VARIABLES_TestExpand __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_ivar_t),
        1,
        {{(unsigned long int *)&OBJC_IVAR_$_TestExpand$_mustProperty, "_mustProperty", "@\"NSString\"", 3, 8}}
    };
    
    static struct /*_method_list_t*/ {
        unsigned int entsize;  // sizeof(struct _objc_method)
        unsigned int method_count;
        struct _objc_method method_list[3];
    } _OBJC_$_INSTANCE_METHODS_TestExpand __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_objc_method),
        3,
        {{(struct objc_selector *)"setMustProperty:", "v24@0:8@16", (void *)_I_TestExpand_setMustProperty_},
        {(struct objc_selector *)"mustProperty", "@16@0:8", (void *)_I_TestExpand_mustProperty},
        {(struct objc_selector *)"testExpanded", "v16@0:8", (void *)_I_TestExpand_testExpanded}}
    };
    
    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_TestExpand __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_prop_t),
        1,
        {{"mustProperty","T@\"NSString\",C,N,V_mustProperty"}}
    };
    extern "C" unsigned long int OBJC_IVAR_$_TestExpand$_mustProperty __attribute__ ((used, section ("__DATA,__objc_ivar"))) = __OFFSETOFIVAR__(struct TestExpand, _mustProperty);
    
    //setter
    static void _I_TestExpand_setMustProperty_(TestExpand * self, SEL _cmd, NSString * _Nonnull mustProperty) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_b0_wtsz92hn2qg2znkty6jcjtj40000gn_T_TestExpand_539e20_mi_0);
    
        mustProperty = mustProperty;
    }
    // getter
    static NSString * _Nonnull _I_TestExpand_mustProperty(TestExpand * self, SEL _cmd) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_b0_wtsz92hn2qg2znkty6jcjtj40000gn_T_TestExpand_539e20_mi_1);
        return (*(NSString * _Nonnull *)((char *)self + OBJC_IVAR_$_TestExpand$_mustProperty));
    }
    // 方法实现
    static void _I_TestExpand_testExpanded(TestExpand * self, SEL _cmd) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_b0_wtsz92hn2qg2znkty6jcjtj40000gn_T_TestExpand_539e20_mi_2);
    }
    

    上面得到用clang得到的

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc TestExpand+Additions.m -o TestExpand+Additions-arm64.cpp
    

    分类中生成的有:属性变量:_prop_list_t 方法:_method_list_t(setter 和getter)

    static struct /*_method_list_t*/ {
        unsigned int entsize;  // sizeof(struct _objc_method)
        unsigned int method_count;
        struct _objc_method method_list[3];
    } _OBJC_$_CATEGORY_INSTANCE_METHODS_TestExpand_$_Additions __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_objc_method),
        3,
        {{(struct objc_selector *)"setMustProperty:", "v24@0:8@16", (void *)_I_TestExpand_Additions_setMustProperty_},
        {(struct objc_selector *)"mustProperty", "@16@0:8", (void *)_I_TestExpand_Additions_mustProperty},
        {(struct objc_selector *)"testExpanded", "v16@0:8", (void *)_I_TestExpand_Additions_testExpanded}}
    };
    // 属性
    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_TestExpand_$_Additions __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_prop_t),
        1,
        {{"mustProperty","T@\"NSString\",C,N"}}
    };
    // setter
    static void _I_TestExpand_Additions_setMustProperty_(TestExpand * self, SEL _cmd, NSString * _Nonnull mustProperty) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_b0_wtsz92hn2qg2znkty6jcjtj40000gn_T_TestExpand_Additions_d05806_mi_0);
    
        objc_setAssociatedObject(self, thisisname, mustProperty, OBJC_ASSOCIATION_COPY);
    }
    
    // getter
    static NSString * _Nonnull _I_TestExpand_Additions_mustProperty(TestExpand * self, SEL _cmd) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_b0_wtsz92hn2qg2znkty6jcjtj40000gn_T_TestExpand_Additions_d05806_mi_1);
        return objc_getAssociatedObject(self, thisisname);
    }
    // 方法实现
    static void _I_TestExpand_Additions_testExpanded(TestExpand * self, SEL _cmd) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_b0_wtsz92hn2qg2znkty6jcjtj40000gn_T_TestExpand_Additions_d05806_mi_2);
    }
    

    通过调用我们可以看出

       TestExpand *expand = [[TestExpand alloc]init];
        expand.mustProperty = @"99999";
        [expand testExpanded];
        NSLog(@"mustProperty====%@",expand.mustProperty);
    

    调用打印结果为:

     这是延展里面的mustProperty
    这是延展里面的=======testExpanded
    这是延展里面的
     mustProperty====99999
    

    我们可以看出类中的属性方法被分类中的属性方法所覆盖。也就是说类本身的方法没有被执行,这里说的覆盖和我们说的值覆盖不一样。我们在声明方法和属性的时候,这个时候告诉编译器我们有这样一个属性和方法。当在进行消息转发的时候优先调用分类里的方法和属性。

    那么这里有一个问题:两个不同分类里面的属性和方法都一样的情况下是怎么执行的呢?
    答:这和分类的编译顺序有关。编译顺序在 TARGETS->Build Phases->Compile Sources

    Compile Sources.png

    分类具有相同的方法和属性的时候优先编译的被覆盖。

    相关文章

      网友评论

          本文标题:在iOS中分类和类中添加属性和方法的区别

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