美文网首页
isKindOfClass和isMemberOfClass的区别

isKindOfClass和isMemberOfClass的区别

作者: Kates | 来源:发表于2021-06-21 13:51 被阅读0次

    判断对象类型

    -(BOOL) isKindOfClass: classObj判断是否是这个类或者这个类的子类的实例

    -(BOOL) isMemberOfClass: classObj 判断是否是这个类的实例

    接下来我们来看一道经典面试题:

        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
    

    看到这个结果会不会很诧异,说实话我是很诧异ret3的结果
    既然感到奇怪我们就来深入研究一下isKindOfClass和isMemberOfClass
    首先通过调试我们定位到isKindOfClass的底层调用源码

    BOOL
    objc_opt_isKindOfClass(id obj, Class otherClass)
    {
    #if __OBJC2__
        if (slowpath(!obj)) return NO;
        Class cls = obj->getIsa();
        if (fastpath(!cls->hasCustomCore())) {
            for (Class tcls = cls; tcls; tcls = tcls->getSuperclass()) {
                if (tcls == otherClass) return YES;
            }
            return NO;
        }
    #endif
        return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
    }
    
    + (BOOL)isKindOfClass:(Class)cls {
        for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
            if (tcls == cls) return YES;
        }
        return NO;
    }
    
    - (BOOL)isKindOfClass:(Class)cls {
        for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
            if (tcls == cls) return YES;
        }
        return NO;
    }
    
    这边有个宏__OBJC2__,当版本比较老,会通过objc_megSend调用isKindOfClass方法
    

    \color{#f00}{注意:这边无论是对象还是类调用isKindOfClass底层都是调用这个方法}
    注意到源码Class cls = obj->getIsa();这边拿的是obj的isa指向的类,我们知道对象的isa指向的是类,类的isa指向的是元类
    [(id)[NSObject class] isKindOfClass:[NSObject class]];
    这个拿的是NSObject根类的isa也就是根元类,和NSObject类对比,显然不是,后面通过循环,获取根元类的父类,根元类的父类是NSObject根类和NSObject类对比两个相同,所以返回true

    [(id)[LGPerson class] isKindOfClass:[LGPerson class]];
    同理,LGPerson的元类跟LGPerson类对比不同,而LGPerson元类的父类跟LGPerson也不一样,所以返回false

    [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
    这边拿的是NSObject对象的isa,也就是NSObject类,所以是一样的

    [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];
    这边拿的是LGPerson对象的isa,也就是LGPerson类,所以是一样的

    我们再来看看isMemberOfClass的源码

    1
    + (BOOL)isMemberOfClass:(Class)cls {
        return self->ISA() == cls;
    }
    
    2
    - (BOOL)isMemberOfClass:(Class)cls {
        return [self class] == cls;
    }
    

    这个直接拿isa指针来跟cls对比,接下来我们来分析一下
    BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
    [NSObject class]的isa是根元类,[NSObject class]根类,两个肯定不一样结果为false

    [(id)[LGPerson class] isMemberOfClass:[LGPerson class]]
    [LGPerson class]的isa是LGPerson元类,[LGPerson class]是LGPerson类,结果为false

    [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]
    首先这边调用的是实例方法也就是上面的2这个代码 ,源码里面直接[self class] == cls,我们来分析一下[[NSObject alloc] class]=NSObject 类所以返回true

    [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]]
    同理,[[LGPerson alloc] class] = LGPerson类 所以也是返回true

    相关文章

      网友评论

          本文标题:isKindOfClass和isMemberOfClass的区别

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