0%

Objective-C Runtime 之四 常用 API

objc_getClass

通过字符串获取某一个类。

1
2
3
4
// 通过字符串获取到这个类然后生成一个实例。
Class cls = objc_getClass("Person");
Person *p = [cls new];
[p hello];

objc_getMetaClass 是通过一个字符串获取元类。
object_getClass 是通过一个对象获取其 isa

class_getName

通过一个类获取类名字符串。

1
NSLog(@"%s", class_getName([Person class]));

class_copyIvarList

class_copyIvarList 可以获取变量列表,之后 ivar_getName 可以获得变量名,ivar_getTypeEncoding 可以获得变量类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 用于获取方法列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 用于获取协议列表。

1
__unsafe_unretained Protocol **protocolList = class_copyProtocolList([Person class], &outCount);

class_addIvar

class_addIvar 用于动态添加变量。一个编译好的类是无法添加变量的,但是我们是动态创建并注册一个类,在注册之前为其动态添加变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 给类分配空间
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

即使是以及编译好的类,也可以动态添加方法。

1
2
3
4
5
6
7
8
9
10
11
12

// 获取方法
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 用于交换两个方法的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13

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!