最近跟人交流时,提到一个问题,说iOS分类中不能添加属性。这里探讨一下不能添加的缘由和添加的方法。
首先,建立一个person类,代码以下:atom
XGPerson.hcode
#import <Foundation/Foundation.h> @interface XGPerson : NSObject /// 年龄 @property (nonatomic, copy) NSString *age; /// 性别 @property (nonatomic, copy) NSString *sex; - (void)text1; @end
XGPerson.m对象
#import "XGPerson.h" @implementation XGPerson - (void)text1 { NSLog(@"%s",__func__); } - (void)text2 { NSLog(@"%s",__func__); } @end
在控制器里获取并打印该类的成员变量、属性和方法,代码以下:ci
- (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))); } }
此时控制台输出以下:get
没有分类时.pngit
这里须要提出的是,平时使用@property的时候,系统会自动生成带“_”的成员变量和该变量的setter和getter方法。也就是说,属性至关于一个成员变量加getter和setter方法。那么,在分类里使用@property会是什么样子呢,下面来建立一个分类:
XGPerson+height.hio
#import "XGPerson.h" @interface XGPerson (height) @property (nonatomic, copy) NSString *height; @end
XGPerson+height.mevent
#import "XGPerson+height.h" #import <objc/runtime.h> @implementation XGPerson (height) @end
若是像上面同样只在.h文件里声明height,那么.m文件里会出现两个警告,意思是说没有实现setter和getter方法。class
警告.pngimport
此时在控制器里执行touchesBegan方法,控制台输出以下:
有分类未实现存取方法.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方法,控制台输出以下:
有分类实现存取方法.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方法后,能够认为给这个类添加上了属性。