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

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

  • 属性
    分类通过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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容