使用runtime获取类的方法和变量

使用runtime获取类的方法和变量

获取属性和变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void ycObjc_copyIvar_copyProperies(Class pClass){

unsigned int count = 0;
Ivar *ivars = class_copyIvarList(pClass, &count);
for (unsigned int i=0; i < count; i++) {
Ivar const ivar = ivars[i];
//获取实例变量名
const char*cName = ivar_getName(ivar);
NSString *ivarName = [NSString stringWithUTF8String:cName];
NSLog(@"class_copyIvarList:%@",ivarName);
}
free(ivars);

unsigned int pCount = 0;
objc_property_t *properties = class_copyPropertyList(pClass, &pCount);
for (unsigned int i=0; i < pCount; i++) {
objc_property_t const property = properties[i];
//获取属性名
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
//获取属性值
NSLog(@"class_copyProperiesList:%@",propertyName);
}
free(properties);
}

获取方法列表

1
2
3
4
5
6
7
8
9
10
11
12
void ycObjc_copyMethodList(Class pClass){
unsigned int count = 0;
Method *methods = class_copyMethodList(pClass, &count);
for (unsigned int i=0; i < count; i++) {
Method const method = methods[i];
//获取方法名
NSString *key = NSStringFromSelector(method_getName(method));

NSLog(@"Method, name: %@", key);
}
free(methods);
}

其他runtime方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 获取类名
const char *className = class_getName(pClass);

// 获取元类
Class metaClass = objc_getMetaClass(className);

// 获取对象方法
Method method = class_getInstanceMethod(pClass, @selector(someFunc));

// 获取类方法
Method method = class_getClassMethod(pClass, @selector(someFunc));

// 获取IMP
IMP imp = class_getMethodImplementation(pClass, @selector(someFunc));

一些思考

定义一个 Person 类如下,并取得该类的类和元类,判断以下代码是否能获取到方法

1
2
3
4
5
6
7
8
9
10
@interface Person : NSObject
- (void)instanceFunc;
+ (void)classFunc;
@end

=======

Person *person = [Person alloc];
Class pClass = object_getClass(person);
Class metaClass = objc_getMetaClass(className);

class_getInstanceMethod

1
2
3
4
5
6
7
Method method1 = class_getInstanceMethod(pClass, @selector(instanceFunc));
Method method2 = class_getInstanceMethod(metaClass, @selector(instanceFunc));

Method method3 = class_getInstanceMethod(pClass, @selector(classFunc));
Method method4 = class_getInstanceMethod(metaClass, @selector(classFunc));

// 结果 method1 method4 可以获取到, method2 method3 获取不到

class_getClassMethod

1
2
3
4
5
6
7
Method method1 = class_getClassMethod(pClass, @selector(instanceFunc));
Method method2 = class_getClassMethod(metaClass, @selector(instanceFunc));

Method method3 = class_getClassMethod(pClass, @selector(classFunc));
Method method4 = class_getClassMethod(metaClass, @selector(classFunc));

// 结果全部可以获取到
1
2
3
4
5
6
7
IMP imp1 = class_getMethodImplementation(pClass, @selector(instanceFunc));
IMP imp2 = class_getMethodImplementation(metaClass, @selector(instanceFunc));

IMP imp3 = class_getMethodImplementation(pClass, @selector(classFunc));
IMP imp4 = class_getMethodImplementation(metaClass, @selector(classFunc));

// 都可以获取到 IMP,但是 imp2 和 imp3 相同, 是找不到时默认返回的_objc_msgForward

为什么获取元类的类方法仍然可以获取到方法?

查看objc源码可知可以看到底层获取了 cls->getMeta() 的 instance 方法

1
2
3
4
5
6
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;

return class_getInstanceMethod(cls->getMeta(), sel);
}

继续查看 getMeta 方法

1
2
3
4
Class getMeta() {
if (isMetaClassMaybeUnrealized()) return (Class)this;
else return this->ISA();
}

如果判断是元类的时候,会返回this, 所以对元类获取类方法仍然可以获取到方法

为什么class_getMethodImplementation获取不存在的方法也会返回值?

直接看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
__attribute__((flatten))
IMP class_getMethodImplementation(Class cls, SEL sel)
{
IMP imp;
if (!cls || !sel) return nil;
lockdebug_assert_no_locks_locked_except({ &loadMethodLock });
imp = lookUpImpOrNilTryCache(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
// Translate forwarding function to C-callable external version
if (!imp) {
return _objc_msgForward;
}
return imp;
}

当imp找不到时会返回 _objc_msgForward