在本文中,主要是通过 runtime 去过去对象的特性,比如属性,实例变量和方法等,其中主要使用到的runtime 函数是.
1).class_copyPropertyList—获取一个类的所有属性,如果没有属性count就为0
2).property_getName—获取属性名称
3).objc_property_t—接收class_copyPropertyList返回的属性地址指针
4).free—使用free函数来释放objc_property_t指针数组内存
5).class_copyIvarList—通过传入一个类,获取这个类所有的实例变量
6).ivar_getName—通过传入数组中的一个实例变量元素返回一个实例变量的字符
7).class_copyMethodList—通过传入一个类,获取这个类所有的方法
8).method_getName—-通过传入数组中的一个实例变量元素返回一个方法名称,为一个 SEL方法选择器
9).sel_getName—通过传入的 SEL方法名称,返回方法字符
10).method_getNumberOfArguments—返回由方法接受的参数个数。
上面是在获取属性,实例变量,方法使用到的 runtime 函数,下面通过代码来展示使用方法
People.h 文件
#import <Foundation/Foundation.h>
@interface People : NSObject{
/**
* 添加两个实例变量
*/
NSString *_occupation;//职业
NSString *_nationality;//国籍
}
/**
* 添加两个属性
*/
@property (nonatomic,copy)NSString *name;
@property (nonatomic,assign)NSInteger age;
/**
* 属性方法
*/
- (NSDictionary *)allProperties;
- (NSDictionary *)allIvars;
- (NSDictionary *)allMethods;
@end
People.m文件
#import "People.h"
#import <objc/runtime.h>
@implementation People
- (NSDictionary *)allProperties {
unsigned int count = 0;
/**
* 获取一个类的所有属性,如果没有属性count就为0
*
* @param cls#> 类 description#>
* @param outCount#> 传入一个地址,将返回一个 Int 型的值到该地址 description#>
*
* @return 返回所有属性的一个 c 语言指针,指针指向的是一个数组
*/
objc_property_t *properties = class_copyPropertyList([self class], &count);
NSMutableDictionary *resultDict = [@{} mutableCopy];
for (NSUInteger i = 0 ; i < count; i++) {
/**
* 通过class_copyPropertyList获取所有属性,取到其中的一个
*
* @param properties 传入一个属性
*
* @return 返回该属性的字符
*/
const char *propertyName = property_getName(properties[i]);
//将返回的字符进行 UTF8编码
NSString *name = [NSString stringWithUTF8String:propertyName];
//KVC里面的方法,目的是通过属性获取其值
id propertyValue = [self valueForKey:name];
if (propertyValue) {
resultDict[name] = propertyValue;
}else {
resultDict[name] = @"字典的key对应的value不能为nil哦!";
}
}
// 这里properties是一个数组指针,我们需要使用free函数来释放内存。
free(properties);
return resultDict;
}
- (NSDictionary *)allIvars {
unsigned int count = 0;
/**
* 通过传入一个类,获取这个类所有的实例变量
* 第一个参数 : 传入一个类
* 第二个参数 : 传入一个地址,返回一个 Int 型的值到这个地址
* 返回一个包含所有实例变量的指针
*/
Ivar *ivar = class_copyIvarList([self class], &count);
NSMutableDictionary *resultDict = [@{} mutableCopy];
for (NSUInteger i = 0 ;i < count;i++) {
/**
* 遍历实例变量指针中的其中一个实例变量
*
* @param ivar 传入一个实例变量
*
* @return 返回一个实例变量的字符
*/
const char *ivarName = ivar_getName(ivar[i]);
NSString *name = [NSString stringWithUTF8String:ivarName];
id valueName = [self valueForKey:name];
if (valueName) {
resultDict[name] = valueName;
}else {
resultDict[name] = @"字典的key对应的value不能为nil哦!";
}
}
free(ivar);
return resultDict;
}
- (NSDictionary *)allMethods {
unsigned int count = 0;
NSMutableDictionary *resultDict = [@{} mutableCopy];
Method *methods = class_copyMethodList([self class], &count);
for (NSUInteger i = 0; i<count; i++) {
// 获取方法名称
SEL methodSEL = method_getName(methods[i]);
const char *methodName = sel_getName(methodSEL);
NSString *name = [NSString stringWithUTF8String:methodName];
/**
* 返回由方法接受的参数个数。
* 包含给定的方法接受的参数个数的整数。
*/
int arguments = method_getNumberOfArguments(methods[i]);
NSLog(@"%zd",arguments);
resultDict[name] = @(arguments - 2);
}
free(methods);
return resultDict;
}
@end
main.m文件
#import <Foundation/Foundation.h>
#import "People.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
People *teacherChang = [[People alloc]init];
teacherChang.name = @"苍井空";
teacherChang.age = 18;
[teacherChang setValue:@"老师" forKey:@"occupation"];
NSDictionary *propertyResultDict = [teacherChang allProperties];
for (NSString *propertuResultString in propertyResultDict.allKeys) {
NSLog(@"propertyName:%@, propertyValue:%@",propertuResultString, propertyResultDict[propertuResultString]);
}
NSDictionary *ivarResultDic = [teacherChang allIvars];
for (NSString *ivarName in ivarResultDic.allKeys) {
NSLog(@"ivarName:%@, ivarValue:%@",ivarName, ivarResultDic[ivarName]);
}
NSDictionary *methodResultDic = [teacherChang allMethods];
for (NSString *methodName in methodResultDic.allKeys) {
NSLog(@"methodName:%@, argumentsCount:%@", methodName, methodResultDic[methodName]);
}
}
return 0;
}
通过以上的代码,就成功得获取到了 People 对象的所有属性,实例变量,以及方法,学会这个技能,在开发中可以方便更多!