美文网首页
实例方法和类方法浅析

实例方法和类方法浅析

作者: 蓝胖子的梦 | 来源:发表于2020-09-16 15:29 被阅读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相等

    相关文章

      网友评论

          本文标题:实例方法和类方法浅析

          本文链接:https://www.haomeiwen.com/subject/icfhyktx.html