利用運(yùn)行時(shí)runtime機(jī)制焰薄,我們可以獲取類文件的屬性或者成員變量忠烛,還可以為類(當(dāng)然包括某些分類)動(dòng)態(tài)添加屬性或者成員變量祝沸,要知道蘋果是不允許我們用普通方法為分類增加屬性的猫缭,但是通過(guò)運(yùn)行時(shí)我們就可以做到耘分。
獲取類屬性或者成員變量:
首先有幾個(gè)相關(guān)的API要弄明白:
/** 獲取類所有通過(guò)@property方式聲明的成員變量或者屬性(參數(shù)1:要獲取成員變量或者屬性的類举塔,參數(shù)2:unsigned int變量的指針地址绑警,用來(lái)存放獲取到了多少個(gè)成員變量) */
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
/** 獲取類所有通過(guò)@property以及在@interface大括號(hào)里邊聲明的成員變量或者屬性(參數(shù)1、2傳入?yún)?shù)同上) */
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
有關(guān)這兩個(gè)方法的區(qū)別央渣,請(qǐng)參考這里
首先我們新建一個(gè)PropertyTest
類计盒,在.h
文件中聲明幾個(gè)成員變量和屬性
{
float _webSiteTitle;
float _privateName;
float _privateAttribute;
}
@property (nonatomic, assign) int count;
@property (nonatomic, weak) id delegate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, strong) NSArray *names;
@property (nonatomic, strong) NSNumber *atomicProperty;
在.m
文件中,獲取類所有成員變量以及屬性
// 獲取所有通過(guò)@property方式聲明的屬性
- (void)getAllProperties
{
unsigned int count = 0;
objc_property_t *pros = class_copyPropertyList([self class], &count);
for (unsigned int i=0; i<count; i++) {
objc_property_t pro = pros[i];
// 'property_getName'獲取屬性名稱
const char *proName = property_getName(pro);
// 'property_getAttributes'獲取屬性具體描述
const char *proAttr = property_getAttributes(pro);
NSLog(@"proName:%s proAttr:%s", proName, proAttr);
unsigned int aCount = 0;
objc_property_attribute_t *attrs = property_copyAttributeList(pro, &aCount);
for (int j=0; j<aCount; j++) {
objc_property_attribute_t attr = attrs[j];
// 'objc_property_attribute_t'是個(gè)結(jié)構(gòu)體芽丹,包含'value' 和 'name'兩個(gè)值
const char *attrName = attr.name;
const char *attrValue = attr.value;
NSLog(@"proName:%s value:%s", attrName, attrValue);
}
// 用完之后一定記得手動(dòng)釋放北启,否則會(huì)造成內(nèi)存泄漏
free(attrs);
}
free(pros);
}
// 獲取所有屬性(包括通過(guò)在` {} `里邊聲明的,以及通過(guò)@property方式聲明的)
- (void)getAllMemberVariables
{
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (unsigned int i=0; i<count; i++) {
Ivar ivar = ivars[i];
const char *name = ivar_getName(ivar);
const char *type = ivar_getTypeEncoding(ivar);
NSLog(@"IvarsName:%s encodeType:%s", name, type);
}
free(ivars);
}
+ (void)test
{
PropertyTest *test = [[PropertyTest alloc] init];
[test getAllProperties];
}
首先我們來(lái)看下 getAllProperties 方法打印的結(jié)果:
打印結(jié)果如下:
讓我們來(lái)分析下打印結(jié)果(第1拔第、2咕村、3和4行是一個(gè)屬性)(這里我們只分析一個(gè)屬性的情況,因?yàn)槠渌闆r類似):
第一行:
proName(屬性名):count proAttr(屬性包含的特性):Ti,N,V_count
第二蚊俺、三和四行:
分別是對(duì)第一行中proAttr的詳細(xì)解釋包括屬性名和屬性值懈涛。
那么第一行中打印的proAttr屬性名和屬性值分別代表什么呢?我們?cè)賮?lái)分析春叫,根據(jù)蘋果官方文檔肩钠,一個(gè)屬性的attribute這樣組成: T, ... ,V_屬性名
其中 *1、T表示屬性類型暂殖,比如int類型為Ti价匠,id類型為T@,NSString類型為T@"NSString"
2呛每、中間的...根據(jù)不同類型的屬性而定義為不同的值踩窖,比如'N'表示聲明為conatomic,'C'表示屬性聲明為copy晨横,'&'表示聲明為retain... 以此類推
3洋腮、V_屬性名 表示實(shí)例變量?
更詳細(xì)的情況可以參考蘋果官方文檔的解釋
我們?cè)倏聪峦ㄟ^(guò)方法 getAllMemberVariables 打印的結(jié)果:
由打印結(jié)果我們可以看出手形,這個(gè)方法打印出了我們定義的所有屬性以及成員變量啥供,其中每一行的
第一個(gè)參數(shù):_屬性或者成員變量名稱
第二個(gè)參數(shù):表示變量類型,比如float類型為'f'库糠,int類型為'i'伙狐,NSString類型為'@NSString'... 以此類推
更詳細(xì)的情況可以參考蘋果官方文檔的解釋
有了這兩個(gè)方法,那么我們?cè)趧?dòng)態(tài)地獲取某個(gè)類的變量的時(shí)候就方便了很多瞬欧,相似的贷屎,runtime中也有獲取類的方法(method)、協(xié)議(protocol)等列表的API艘虎,有興趣的朋友可以去學(xué)習(xí)下