iOS分类不能添加属性原因的探索

2018-09-20  本文已影响0人  mengyingguo

首先,创建一个person类,代码如下:
.h

#import <Foundation/Foundation.h>
 
@interface XGPerson : NSObject
/// 年龄
@property (nonatomic, copy) NSString *age;
/// 性别
@property (nonatomic, copy) NSString *sex;
 
- (void)text1;
 
@end

.m

#import "XGPerson.h"
 
@implementation XGPerson
 
- (void)text1 {
    NSLog(@"%s",__func__);
}
 
- (void)text2 {
    NSLog(@"%s",__func__);
}
@end

在控制器里获取并打印该类的成员变量、属性和方法,代码如下:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    // 获取成员变量
    unsigned int ivarCount = 0;
    Ivar *ivars = class_copyIvarList([XGPerson class], &ivarCount);
    for (int i = 0; i < ivarCount; i++) {
        Ivar ivar = ivars[I];
        NSLog(@"第%d个成员变量:%s",i,ivar_getName(ivar));
    }
    free(ivars);
    // 获取属性
    unsigned int propertyCount = 0;
    objc_property_t *propertyList = class_copyPropertyList([XGPerson class], &propertyCount);
    for (int i = 0; i < propertyCount; i++) {
        objc_property_t property = propertyList[I];
        NSLog(@"第%d个属性:%s",i,property_getName(property));
    }
    
    
    // 获取方法列表
    unsigned int methodCount = 0;
    Method *methods = class_copyMethodList([XGPerson class], &methodCount);
    for (int i = 0; i < methodCount; i++) {
        Method method = methods[I];
        
        NSLog(@"第%d个方法:%s",i, sel_getName(method_getName(method)));
    }
    
}
 

image.png

这里需要提出的是,平时使用@property的时候,系统会自动生成带“_”的成员变量和该变量的setter和getter方法。也就是说,属性相当于一个成员变量加getter和setter方法。那么,在分类里使用@property会是什么样子呢,下面来创建一个分类:

XGPerson+height.h

#import "XGPerson.h"
 
@interface XGPerson (height)
 
@property (nonatomic, copy) NSString *height;
 
@end

XGPerson+height.m

#import "XGPerson+height.h"
 
#import <objc/runtime.h>
 
@implementation XGPerson (height)
 
 
@end

如果像上面一样只在.h文件里声明height,那么.m文件里会出现两个警告,意思是说没有实现setter和getter方法。


image.png

此时在控制器里执行touchesBegan方法,控制台输出如下:

image.png

可以看到,此时person类里并没有添加带“_”的成员变量,也没有实现setter和getter方法,只是在属性列表里添加了height属性。并且此时如果在控制器里调用self.height,程序运行时会报错,显示找不到该方法。实现一下person分类里的两个方法:
XGPerson+height.m

#import "XGPerson+height.h"
 
#import <objc/runtime.h>
 
@implementation XGPerson (height)
 
 - (NSString *)height {
 
 }
 
 - (void)setHeight:(NSString *)height {
 
 }
 
@end

此时在控制器里执行touchesBegan方法,控制台输出如下:


image.png

可以看到即使实现了setter和getter方法,也仍然没有添加带“”的成员变量,也就是说,在setter和getter方法里仍然不能直接访问以下划线开头的成员变量,因为在分类里用@property声明属性时系统并没有添加以“”开头的成员变量。此时要达到添加的目的可以使用运行时的关联对象。示例代码如下:
XGPerson+height.m

#import "XGPerson+height.h"
 
#import <objc/runtime.h>
 
@implementation XGPerson (height)
 
 
 
 - (NSString *)height {
 return objc_getAssociatedObject(self, @"height");
 }
 
 
 - (void)setHeight:(NSString *)height {
 objc_setAssociatedObject(self, @"height", height, OBJC_ASSOCIATION_COPY_NONATOMIC);
 }
 
@end

当然也可以在setter和getter方法里访问该类其他的属性,比如在UIView的分类的里添加x、y属性,可以直接返回self.frame.origin.x和self.frame.origin.y。

总结

在分类里使用@property声明属性,只是将该属性添加到该类的属性列表,并声明了setter和getter方法,但是没有生成相应的成员变量,也没有实现setter和getter方法。所以说分类不能添加属性。但是在分类里使用@property声明属性后,又实现了setter和getter方法,那么在这个类以外可以正常通过点语法给该属性赋值和取值。就是说,在分类里使用@property声明属性,又实现了setter和getter方法后,可以认为给这个类添加上了属性。

上一篇下一篇

猜你喜欢

热点阅读