class_copyPropertyList
class_copyPropertyList
是来获取属性的- 只能获取到 @property 声明的属性
使用runtime获取类私有属性,首先需要导入 #import <objc/runtime.h>
获取属性列表的方法是
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
举个例子
Person 声明两个属性name和age
#import "Person.h"
@interface Person ()
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *age;
@end
@implementation Person
@end
使用 class_copyPropertyList
方法获取Person的私有属性
Person *person = [[Person alloc] init];
id personClass = objc_getClass("Person");
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(personClass, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSString *propName = [NSString stringWithUTF8String:property_getName(property)];
id value = [person valueForKey:propName];
fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
}
打印结果如下
name T@"NSString",C,N,V_nameage T@"NSString",C,N,V_age
但是有一个问题,如果类从其它的类继承过来的,父类的属性将不会被copy出来
举个例子
@interface Son : Person
@end
@interface Son ()
@property (nonatomic, copy) NSString *birthday;
@property (nonatomic, copy) NSString *sex;
@end
@implementation Son
@end
Son类继承Person类,我们同样的方法打印一下Son类的属性列表,结果如下
birthday T@"NSString",C,N,V_birthday
sex T@"NSString",C,N,V_sex
可以看到只能获取Son类自己的属性,不能获取父类的name和age属性,但项目中使用继承的地方非常多,比如使用AOP实现无埋点时就需要获取父类的属性,那我们怎么获取父类的属性列表呢?
1. 最先想到的方案就是用上述方法 获取的 [son superclass]
的属性列表。
objc_property_t *properties = class_copyPropertyList([son superclass], &outCount);
打印结果:
name T@"NSString",C,N,V_name
age T@"NSString",C,N,V_age</span>
2. 还有一种方法是声明一个Protocol, Protocol中有属性,然后获取Protocol中属性列表,方法如下:
objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)
Protocol *objc_getProtocol(const char *name)
很多场景下我们需要同时获取子类和父类的私有属性,封装了两个方法方便调用
获取指定类的属性以及父类的所有属性
/**
获取指定类的属性
@param cls 被获取属性的类
@return 属性名称 [NSString *]
*/
NSArray * getClassProperty(Class cls) {
if (!cls) return @[];
NSMutableArray * all_p = [NSMutableArray array];
unsigned int a;
objc_property_t * result = class_copyPropertyList(cls, &a);
for (unsigned int i = 0; i < a; i++) {
objc_property_t o_t = result[i];
[all_p addObject:[NSString stringWithFormat:@"%s", property_getName(o_t)]];
}
free(result);
return [all_p copy];
}
/**
获取指定类(以及其父类)的所有属性
@param cls 被获取属性的类
@param until_class 当查找到此类时会停止查找,当设置为 nil 时,默认采用 [NSObject class]
@return 属性名称 [NSString *]
*/
NSArray * getAllProperty(Class cls, Class until_class) {
Class stop_class = until_class ?: [NSObject class];
if (class_getSuperclass(cls) == stop_class) return @[];
NSMutableArray * all_p = [NSMutableArray array];
[all_p addObjectsFromArray:getClassProperty(cls)];
if (class_getSuperclass(cls) == stop_class) {
return [all_p copy];
} else {
[all_p addObjectsFromArray:getAllProperty([cls superclass], stop_class)];
}
return [all_p copy];
}
还有一种场景,我们只知道对象名,不仅要获取对象的私有属性,还要获取属性的内容,可以调用下面的方法
/**
获取对象的所有属性和属性内容
@param obj 对象 @return 所有属性及属性内容 [NSDictionary *] */
+ (NSDictionary *)getAllPropertiesAndVaules:(NSObject *)obj
{
NSMutableDictionary *propsDict = [NSMutableDictionary dictionary];
unsigned int outCount;
objc_property_t *properties =class_copyPropertyList([obj class], &outCount);
for ( int i = 0; i<outCount; i++)
{
objc_property_t property = properties[i];
const char* char_f =property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:char_f];
id propertyValue = [obj valueForKey:(NSString *)propertyName];
if (propertyValue) {
[propsDict setObject:propertyValue forKey:propertyName];
}
}
free(properties);
return propsDict;
}
这里延伸一下另外一个方法,获取私有变量的方法 class_copyIvarList
class_copyIvarList
class_copyIvarList
用来获取所有的变量的- 获取所有的变量,包括 @property 声明的属性和声明的全局变量 如: _name
获取指定类以及其父类所有的变量
/**
获取指定类的变量
@param cls 被获取变量的类
@return 变量名称集合 [NSString *]
*/
NSArray * getClassIvar(Class cls) {
if (!cls) return @[];
NSMutableArray * all_p = [NSMutableArray array];
unsigned int a;
Ivar * iv = class_copyIvarList(cls, &a);
for (unsigned int i = 0; i < a; i++) {
Ivar i_v = iv[i];
[all_p addObject:[NSString stringWithFormat:@"%s", ivar_getName(i_v)]];
}
free(iv);
return [all_p copy];
}
/**
获取指定类(以及其父类)的所有变量
@param cls 被获取变量的类
@param until_class 当查找到此类时会停止查找,当设置为 nil 时,默认采用 [NSObject class]
@return 变量名称集合 [NSString *]
*/
NSArray * getAllIvar(Class cls, Class until_class) {
Class stop_class = until_class ?: [NSObject class];
if (class_getSuperclass(cls) == stop_class) return @[];
NSMutableArray * all_p = [NSMutableArray array];
[all_p addObjectsFromArray:getClassIvar(cls)];
if (class_getSuperclass(cls) == stop_class) {
return [all_p copy];
} else {
[all_p addObjectsFromArray:getAllIvar([cls superclass], stop_class)];
}
return [all_p copy];
}
总结
-
class_copyPropertyList
只能获取到 @property 声明的属性 -
class_copyIvarList
用来获取所有的变量的 -
以上两个方法都只能获取到当前类的属性和变量,获取不到父类的属性和变量
-
class_copyMethodList
是获取类的所有方法的