iOS

runtime应用

Posted by 易博 on March 27, 2018

Runtime运行时是OC语言的一个特性,开发者可以在运行时中做甚多事情,下面主要介绍几种常用的应用,那就是获取类的实例变量、属性、方法列表。

创建一个用于测试的类,具体实现如下

//UserModel.h

#import "Person.h"

@interface UserModel : Person

@property (nonatomic,strong) NSString *username;

@property (nonatomic,assign) NSInteger age;

-(void)updateUserInfo:(NSDictionary *)info;

+(NSDictionary *)getUserInfo;

@end

//UserModel.m

#import "UserModel.h"

@interface UserModel()
{
    NSString *sex;
    NSString *userid;
}

@property (nonatomic,strong) NSString *mark;

@end

@implementation UserModel

-(void)updateUserInfo:(NSDictionary *)info
{
    
}

+(NSDictionary *)getUserInfo
{
    return @{};
}

-(void)instanceMethod
{
    
}

+(void)classMethod
{
    
}

@end

一、获取属性列表

u_int  count;
objc_property_t *properties = class_copyPropertyList([UserModel class], &count);
for (int i = 0; i < count ; i++)
{
    const char *propertyName = property_getName(properties[i]);
    NSString *strName = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
    NSLog(@"属性名称:%@",strName);
}
//properties属于链表指针,使用完后需要释放
free(properties);

二、获取实例变量列表

UserModel *userModel = [[UserModel alloc]init];
unsigned int count = 0;
Ivar *Ivars = class_copyIvarList([UserModel class], &count);
for (unsigned int i = 0; i < count; i++) {
    Ivar ivar = Ivars[i];
    const char * name = ivar_getName(ivar);
    //修改实例变量的值,修改私有变量的值可以通过KVC和Runtime来实现
    if (0 == strcmp(name, "userid")) {
        object_setIvar(userModel, Ivars[i], @"100002");
    }
    else if (0 == strcmp(name, "_age")) {
        object_setIvar(userModel, Ivars[i], @(30));
    }
    NSLog(@"实例变量描述为: %s ", name);
}
free(Ivars);

三、获取对象方法列表

u_int count;
Method *methods= class_copyMethodList([UserModel class], &count);
for (int i = 0; i < count ; i++)
{
    SEL name = method_getName(methods[i]);
    NSString *strName = [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding];
    NSLog(@"实例方法名称:%@",strName);
}
free(methods);

四、获取类方法列表 类本身也是一个对象,所以获取类方法可以找到类的元类,然后获取其实例方法列表

u_int  count;
const char *clsName = class_getName([UserModel class]);
Class metaClass = objc_getMetaClass(clsName);
Method *methods= class_copyMethodList(metaClass, &count);
for (int i = 0; i < count ; i++)
{
    SEL name = method_getName(methods[i]);
    NSString *strName = [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding];
    NSLog(@"类方法名称:%@",strName);
}
free(methods);

下图是上面运行结果的截图,从截图可以看到,此方法是无法获取父类的属性、实例变量等,获取方法时自动合成的set和get方法也能获取到。自动合成的实例变量会在属性名称前加上下划线