metaclass作用——属性,类方法与实例方法

272 阅读3分钟

问题/目标分析

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中保存类型方法