问题/目标分析
metaclass的具体作用,属性,方法等。
方法分析
使用objc runtime来打印class和metaclass信息。
实验步骤
测试实例
@interface BLPerson : NSObject{
NSString *hobby;
int int_value;
}
@property (nonatomic, copy) NSString *name;
-(void)run;
-(void)walk;
+(void)classMethod;
@implementation BLPerson
//- (void)run{
// NSLog(@"%s",__func__);
//}
- (void)walk{
NSLog(@"%s",__func__);
}
+(void)classMethod
{
NSLog(@"%s",__func__);
}
@end
测试方法
1、testPrintValue
测试在测试实例中的,成员变量hobby,int_value以及属性name。
void testObjc_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);
}
+(void)testPrintValue
{
@autoreleasepool {
BLPerson *person = [BLPerson alloc];
Class pClass = object_getClass(person);
testObjc_copyIvar_copyProperies(pClass);
NSLog(@"%@ - %p",person,pClass);
}
}
2019-12-24 21:23:30.015464+0800 Test_pro[4059:2220121] class_copyIvarList:hobby
2019-12-24 21:23:30.016042+0800 Test_pro[4059:2220121] class_copyIvarList:int_value
2019-12-24 21:23:30.016078+0800 Test_pro[4059:2220121] class_copyIvarList:_name
2019-12-24 21:23:30.016135+0800 Test_pro[4059:2220121] class_copyProperiesList:name
2019-12-24 21:23:30.016177+0800 Test_pro[4059:2220121] <BLPerson: 0x2820fbb20> - 0x102eae170
发现属性name,在类的内部存在_name形式.
2、testPrintFunc
测试打印实例方法,run,walk,以及类型方法classMethod.
void testObjc_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);
NSLog(@"Metaclass");
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
methods = class_copyMethodList(metaClass, &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);
}
+(void)testPrintFunc
{
@autoreleasepool {
BLPerson *person = [BLPerson alloc];
Class pClass = object_getClass(person);
testObjc_copyMethodList(pClass);
}
}
2019-12-24 21:25:37.034811+0800 Test_pro[4062:2221237] Method, name: walk
2019-12-24 21:25:37.035622+0800 Test_pro[4062:2221237] Method, name: name
2019-12-24 21:25:37.035672+0800 Test_pro[4062:2221237] Method, name: .cxx_destruct
2019-12-24 21:25:37.035710+0800 Test_pro[4062:2221237] Method, name: setName:
2019-12-24 21:25:37.035749+0800 Test_pro[4062:2221237] Metaclass
2019-12-24 21:25:37.035783+0800 Test_pro[4062:2221237] Method, name: classMethod
在classs中发现属性name的 get,set方法,以及实例方法walk。 在metaclass 中发现类型方法classMethod。
3、testPrintMetaMethod
对比class_getInstanceMethod,和class_getClassMethod,两种方法的不同表现。
void testInstanceMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getInstanceMethod(pClass, @selector(walk));
Method method2 = class_getInstanceMethod(metaClass, @selector(walk));
Method method3 = class_getInstanceMethod(pClass, @selector(classMethod));
Method method4 = class_getInstanceMethod(metaClass, @selector(classMethod));
NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
}
void testClassMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getClassMethod(pClass, @selector(walk));
Method method2 = class_getClassMethod(metaClass, @selector(walk));
Method method3 = class_getClassMethod(pClass, @selector(classMethod));
Method method4 = class_getClassMethod(metaClass, @selector(classMethod));
NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
}
/** 打印类方法和实例方法*/
+(void)testPrintMetaMethod
{
@autoreleasepool {
BLPerson *person = [BLPerson alloc];
Class pClass = object_getClass(person);
testInstanceMethod_classToMetaclass(pClass);
testClassMethod_classToMetaclass(pClass);
}
}
2019-12-24 21:25:57.911364+0800 Test_pro[4065:2221632] 0x100dad978-0x0-0x0-0x100dad910
2019-12-24 21:25:57.912004+0800 Test_pro[4065:2221632] 0x0-0x0-0x100dad910-0x100dad910
说明类方法在metaclass中,实例方法在class中。
4、testPrintIMP
测试 class_getMethodImplementation方法的行为。
void testIMP_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
IMP imp1 = class_getMethodImplementation(pClass, @selector(walk));
IMP imp2 = class_getMethodImplementation(metaClass, @selector(walk));
IMP imp3 = class_getMethodImplementation(pClass, @selector(classMethod));
IMP imp4 = class_getMethodImplementation(metaClass, @selector(classMethod));
NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
}
+(void)testPrintIMP
{
@autoreleasepool {
BLPerson *person = [BLPerson alloc];
Class pClass = object_getClass(person);
testIMP_classToMetaclass(pClass);
}
}
2019-12-24 21:26:16.611959+0800 Test_pro[4067:2222013] 0x102c9d9d0-0x19be91500-0x19be91500-0x102c9da0c
说明 class_getMethodImplementation 查询方法,范围会更大。
结果分析
属性分为成员变量和属性变量。 属性变量 = 成员变量 + getter + setter
class中保存实例方法 metaclass中保存类型方法