实例方法和类方法浅析

2020-09-16  本文已影响0人  蓝胖子的梦

实例方法和类方法浅析

  1. 代码片段
void lgObjc_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));
        
        LGLog(@"Method, name: %@", key);
    }
    free(methods);
}
LGPerson *person = [LGPerson alloc];
Class pClass     = object_getClass(person);
lgObjc_copyMethodList(pClass);       

打印结果:

Method, name: sayHello

结论:实例方法存在类对象中,类方法存在元类对象中

  1. 代码片段
void lgInstanceMethod_classToMetaclass(Class pClass){
    
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    /// - (void)sayHello;
    /// + (void)sayHappy;
    Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
    Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));

    Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
    Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));
    
    LGLog(@"%s - %p - %p - %p - %p",__func__,method1,method2,method3,method4);
}
void lgClassMethod_classToMetaclass(Class pClass){
    
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    /// - (void)sayHello;
    /// + (void)sayHappy;
    Method method1 = class_getClassMethod(pClass, @selector(sayHello));
    Method method2 = class_getClassMethod(metaClass, @selector(sayHello));

    Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
    Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
    
    LGLog(@"%s - %p - %p - %p - %p",__func__,method1,method2,method3,method4);
}

其结果为:

lgInstanceMethod_classToMetaclass - 0x100003358 - 0x0 - 0x0 - 0x1000032f0
lgClassMethod_classToMetaclass - 0x0 -0x0 - 0x1000032f0 - 0x1000032f0

分析:

    for (unsigned attempts = unreasonableClassCount();;) {
        // curClass method list.
        Method meth = getMethodNoSuper_nolock(curClass, sel);
        if (meth) {
            imp = meth->imp;
            goto done;
        }

        if (slowpath((curClass = curClass->superclass) == nil)) {
            // No implementation found, and method resolver didn't help.
            // Use forwarding.
            imp = forward_imp;
            break;
        }

        // Halt if there is a cycle in the superclass chain.
        if (slowpath(--attempts == 0)) {
            _objc_fatal("Memory corruption in class list.");
        }

        // Superclass cache.
        imp = cache_getImp(curClass, sel);
        if (slowpath(imp == forward_imp)) {
            // Found a forward:: entry in a superclass.
            // Stop searching, but don't cache yet; call method
            // resolver for this class first.
            break;
        }
        if (fastpath(imp)) {
            // Found the method in a superclass. Cache it in this class.
            goto done;
        }
    }

class_getInstanceMethod当前类或者父类没有该实例方法就会返回NULL

Method class_getClassMethod(Class cls, SEL sel)
{
    if (!cls  ||  !sel) return nil;

    return class_getInstanceMethod(cls->getMeta(), sel);
}
// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
    if (isMetaClass()) return (Class)this;
    else return this->ISA();
}

class_getClassMethod当前类或者父类没有该类方法就会返回NULL
第一个0x100003358:pClass是LGPerson,当前LGPerson类存在sayHello实例方法。
第二个0x0:metaClass是LGPerson类的元类,LGPerson类的元类不存在sayHello实例方法。按走位图继续查找根元类(NSObject)->根类(NSObject)->nil,都没有sayHello,最终返回NULL。
第三个0x0:pClass是LGPerson类,当前LGPerson类不存在sayHappy实例方法。按走位图继续查找根类(NSObject)->nil,都没有sayHello,最终返回NULL。
第四个0x1000032f0:metaClass是LGPerson类的元类,LGPerson类的元类存在sayHappy实例方法。对于LGPerson类的元类来说,sayHappy是一个实例方法。
第五个0x0:pClass是LGPerson类,pClass不是元类,则取LGPerson的元类,当前LGPerson的元类不存在sayHello方法。按走位图继续查找根元类(NSObject)-->根类(NSObject)->nil,都没有sayHello类方法,最终返回NULL。
第六个0x0:metaClass是LGPerson类的元类,当前LGPerson类的元类不存在sayHello方法。按走位图继续查找根元类(NSObject)->根类(NSObject)->nil,都没有sayHello类方法,最终返回NULL。
第七个0x1000032f0:pClass是LGPerson类,pClass不是元类,则取LGPerson的元类,当前LGPerson元类存在sayHappy类方法。
第八个0x1000032f0:metaClass是LGPerson类的元类,当前LGPerson元类存在sayHappy类方法。

        BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];       //
        BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];     //
        BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];       //
        BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];     //
        NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);

        BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];       //
        BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];     //
        BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];       //
        BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];     //
        NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);

其结果为:

 re1 :1
 re2 :0
 re3 :0
 re4 :0
 re5 :1
 re6 :1
 re7 :1
 re8 :1

查看 +isKindOfClass +isKindOfMember源码

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

依次遍历元类-->根元类-->根类-->nil,判断是否跟传入的cls相等

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

判断元类是否跟传入的cls相等

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

依次遍历对象的类-->父类-->根类-->nil,判断是否跟传入的cls相等

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

判断对象的类是否跟传入的cls相等

re1 :1 依次遍历元类NSObject-->根元类NSObject-->根类NSObject(此处相等)-->nil,判断是否跟传入的NSObject相等。
re2 :0 判断NSObject元类是否跟传入的NSObject根类相等。NSObject元类 != NSObject
re3 :0 依次遍历LGPerson元类-->NSObject根元类-->NSObject根类-->nil,判断是否跟传入的LGPerson相等。
re4 :0 判断LGPerson元类是否跟传入的LGPerson相等。LGPerson元类 != LGPerson
re5 :1 依次遍历NSObject类-->nil,判断是否跟传入的NSObject相等
re6 :1 判断NSObject类是否跟传入的NSObject相等
re7 :1 依次遍历LGPerson-->NSObject父类-->NSObject根类-->nil,判断是否跟传入的LGPerson相等
re8 :1 判断LGPerson是否跟传入的LGPerson相等

上一篇 下一篇

猜你喜欢

热点阅读