上一篇文章讲解了iOS类底层结构之LLDB分析,这篇文章将使用API分析方式来补充和理解LLDB分析结果。
前言
类声明相关如下:
@interface WJPerson : NSObject {
NSString *hobby;
}
// isa
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
- (void)instanceMethod;
+ (void)classMethod;
@end
一、获取类的成员变量
这里使用class_copyIvarList成员变量列表
void wj_Ivars_OfClass(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(@"\n%@变量名:%@\n",NSStringFromClass(pClass),ivarName);
}
free(ivars);
}
调用方法输出如下:
2021-06-28 01:29:28.489493+0800 KCObjcBuild[6221:550030]
WJPerson变量名:hobby
2021-06-28 01:29:28.493262+0800 KCObjcBuild[6221:550030]
WJPerson变量名:_name
2021-06-28 01:29:28.493688+0800 KCObjcBuild[6221:550030]
WJPerson变量名:_nickName
其中_name和_nickName是由于属性name和nickeName底层生成的。
二、获取类的属性
使用class_copyPropertyList获取属性列表
void wj_Properties_OfClass(Class pClass) {
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(@"\n%@属性名:%@\n",NSStringFromClass(pClass),propertyName);
}
free(properties);
}
调用方法输出如下:
2021-06-28 01:29:28.493856+0800 KCObjcBuild[6221:550030]
WJPerson属性名:name
2021-06-28 01:29:28.493977+0800 KCObjcBuild[6221:550030]
WJPerson属性名:nickName
三、获取类的方法
3.1使用class_copyMethodList获取类的方法列表
void wj_MethodList_OfClass(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(@"\n%@方法名:--%@--\n",NSStringFromClass(pClass),key);
}
free(methods);
}
调用输出如下:
2021-06-28 01:29:28.494550+0800 KCObjcBuild[6221:550030]
WJPerson方法名:--instanceMethod--
2021-06-28 01:29:28.494683+0800 KCObjcBuild[6221:550030]
WJPerson方法名:--name--
2021-06-28 01:29:28.495075+0800 KCObjcBuild[6221:550030]
WJPerson方法名:--setName:--
2021-06-28 01:29:28.496136+0800 KCObjcBuild[6221:550030]
WJPerson方法名:--nickName--
2021-06-28 01:29:28.496270+0800 KCObjcBuild[6221:550030]
WJPerson方法名:--setNickName:--
3.1 结论
获取不到类方法+ (void)classMethod,符合之前LLDB调试结果,我们在以其它方式找下看;
3.2使用class_getInstanceMethod获取类的实例方法列表
void wj_InstanceMethod_On_Class_And_MetaClass(Class pClass,SEL instanceSel,SEL classSel) {
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getInstanceMethod(pClass, instanceSel);
Method method2 = class_getInstanceMethod(metaClass, instanceSel);
Method method3 = class_getInstanceMethod(pClass, classSel);
Method method4 = class_getInstanceMethod(metaClass, classSel);
NSLog(@"\n实例方法验证\n%@实例方法中%@方法%@\n%@元类实例方法中%@方法%@\n",NSStringFromClass(pClass),method1?@"存在":@"不存在",NSStringFromSelector(instanceSel),NSStringFromClass(pClass),method2?@"存在":@"不存在",NSStringFromSelector(instanceSel));
NSLog(@"\n实例方法验证\n%@实例方法中%@方法%@\n%@元类实例方法中%@方法%@\n",NSStringFromClass(pClass),method3?@"存在":@"不存在",NSStringFromSelector(classSel),NSStringFromClass(pClass),method4?@"存在":@"不存在",NSStringFromSelector(classSel));
}
调用输出如下:
2021-06-28 01:29:28.496569+0800 KCObjcBuild[6221:550030]
实例方法验证
WJPerson实例方法中存在方法instanceMethod
WJPerson元类实例方法中不存在方法instanceMethod
2021-06-28 01:29:28.496691+0800 KCObjcBuild[6221:550030]
实例方法验证
WJPerson实例方法中不存在方法classMethod
WJPerson元类实例方法中存在方法classMethod
3.2 结论
3.2.1 在类的实例方法中能找到实例方法
3.2.2 在元类的实例方法找不到实例方法
3.2.3 在类的实例方法中找不到类方法
3.2.4 在元类的实例方法中的能找到类方法
3.3使用class_getClassMethod获取类的实例方法列表
class_getClassMethod源码如下:
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
使用class_getClassMethod方法
void wj_ClassMethod_On_Class_And_MetaClass(Class pClass,SEL instanceSel,SEL classSel) {
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getClassMethod(pClass, instanceSel);
Method method2 = class_getClassMethod(metaClass, instanceSel);
Method method3 = class_getClassMethod(pClass, classSel);
Method method4 = class_getClassMethod(metaClass, classSel);
NSLog(@"\n类方法验证\n%@类方法中%@方法%@\n%@元类方法中%@方法%@\n",NSStringFromClass(pClass),method1?@"存在":@"不存在",NSStringFromSelector(instanceSel),NSStringFromClass(pClass),method2?@"存在":@"不存在",NSStringFromSelector(instanceSel));
NSLog(@"\n类方法验证\n%@类方法中%@方法%@\n%@元类方法中%@方法%@\n",NSStringFromClass(pClass),method3?@"存在":@"不存在",NSStringFromSelector(classSel),NSStringFromClass(pClass),method4?@"存在":@"不存在",NSStringFromSelector(classSel));
}
调用输出如下:
2021-06-28 01:29:28.496943+0800 KCObjcBuild[6221:550030]
类方法验证
WJPerson类方法中不存在方法instanceMethod
WJPerson元类方法中不存在方法instanceMethod
2021-06-28 01:29:28.497063+0800 KCObjcBuild[6221:550030]
类方法验证
WJPerson类方法中存在方法classMethod
WJPerson元类方法中存在方法classMethod
3.3 结论
3.3.1 在类的类方法中找不到实例方法
3.3.2 在元类的类方法找不到实例方法
3.3.3 在类的类方法中能找到类方法,其实是在元类中找到的(见class_getClassMethod源码)。
3.3.4 在元类的类方法中能找到类方法,其实也是在元类中找到的(见class_getClassMethod源码)。
3.3.5 由class_getClassMethod 源码得知,OC底层只有实例方法,没有类方法。
四、总结
从以上得知,结论和使用LLDB分析时获取类的成员变量、属性、方法列表(实例方法、类方法)相同。