Objective-C Runtime 之四 常用 API
objc_getClass
通过字符串获取某一个类。
// 通过字符串获取到这个类然后生成一个实例。
Class cls = objc_getClass("Person");
Person *p = [cls new];
[p hello];
objc_getMetaClass是通过一个字符串获取元类。object_getClass是通过一个对象获取其isa。
class_getName
通过一个类获取类名字符串。
NSLog(@"%s", class_getName([Person class]));
class_copyIvarList
class_copyIvarList 可以获取变量列表,之后 ivar_getName 可以获得变量名,ivar_getTypeEncoding 可以获得变量类型。
unsigned int outCount = 0;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSUInteger i = 0; i < outCount; i++) {
Ivar ivar = ivarList[i];
NSLog(@"%s", ivar_getName(ivar));
NSLog(@"%s", ivar_getTypeEncoding(ivar));
}
/*
_name
@"NSString"
_age
q
*/
class_copyPropertyList
class_copyPropertyList 用于获取属性列表。property_getName 用于获取属性名,property_getAttributes 用于获取属性内容。
其中,关于属性中编码含义参见 Declared Properties
unsigned int outCount = 0;
objc_property_t *propertyList = class_copyPropertyList([Person class], &outCount);
for (NSUInteger i = 0; i < outCount; i++) {
objc_property_t p = propertyList[i];
NSLog(@"%s", property_getName(p));
NSLog(@"%s", property_getAttributes(p));
}
/*
name
T@"NSString",C,N,V_name
age
Tq,N,V_age
*/
class_copyMethodList
class_copyMethodList 用于获取方法列表
unsigned int outCount = 0;
Method *methodList = class_copyMethodList([Person class], &outCount);
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSUInteger i = 0; i < outCount; i++) {
Method method = methodList[i];
SEL sel = method_getName(method);
dict[NSStringFromSelector(sel)] = [NSString stringWithUTF8String:method_getTypeEncoding(method)];
}
NSLog(@"%@", dict);
/*
{
".cxx_destruct" = "v16@0:8";
age = "q16@0:8";
"helloTo:" = "v24@0:8@16";
name = "@16@0:8";
"setAge:" = "v24@0:8q16";
"setName:" = "v24@0:8@16";
walk = "v16@0:8";
}
*/
class_copyProtocolList
class_copyProtocolList 用于获取协议列表。
__unsafe_unretained Protocol **protocolList = class_copyProtocolList([Person class], &outCount);
class_addIvar
class_addIvar 用于动态添加变量。一个编译好的类是无法添加变量的,但是我们是动态创建并注册一个类,在注册之前为其动态添加变量。
// 给类分配空间
Class Game = objc_allocateClassPair([NSObject class], "Game", 0);
// 添加变量
BOOL isAdded = class_addIvar(Game, "name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
// 注册类
objc_registerClassPair(Game);
if (isAdded) {
id game = [[Game alloc] init];
[game setValue:@"mario" forKey:@"name"];
NSLog(@"%@", game);
NSLog(@"%@", [game valueForKey:@"name"]);
}
// <Game: 0x1006aaba0>
// mario
class_addMethod
即使是以及编译好的类,也可以动态添加方法。
// 获取方法
Method method = class_getInstanceMethod([Person class], @selector(hello));
// 获取方法实现
IMP methodIMP = method_getImplementation(method);
// 获取方法类型(即返回值、参数类型)
const char *types = method_getTypeEncoding(method);
class_addMethod([Animal class], @selector(hi), methodIMP, types);
Animal *a = [Animal new];
[a hi];
本例将 Person 类的一个方法添加给了 Animal 类中。
method_exchangeImplementations
method_exchangeImplementations 用于交换两个方法的实现。
Method method1 = class_getInstanceMethod([Person class], @selector(hello));
Method method2 = class_getInstanceMethod([Person class], @selector(walk));
method_exchangeImplementations(method1, method2);
Person *p = [Person new];
[p hello];
[p walk];
// Walk!
// Hello!
本例我们交换了两个方法的实现,最终调用 hello 输出 Walk!,调用 walk 输出 Hello!。