理解isKindOfClass和isMemberOfClass的区别

前两天看到一个面试题突然挺感兴趣的,然后发现自己并不能立马分析出底层原理实现,这里抓紧看了一下runtime源码并按照自己的理解分析了一波,然后得出答案。

1.面试题

BOOL result1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL result2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL result3 = [[Person class] isKindOfClass:[Person class]];
BOOL result4 = [[Person class] isMemberOfClass:[Person class]];
BOOL result5 = [[Person class] isKindOfClass:[NSObject class]];

2.初步分析

我们了解到isKindOfClass是通常是用来判断A对象是否为B类的实例或其子类的实例对象,官方说明如下:

Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class.

isMemberOfClass常用来判断A对象是否为B类的实例对象。

Returns a Boolean value that indicates whether the receiver is an instance of a given class.

既然是判断实例,那么这里的A应该是实例对象才对,而题中A都是Class类。
所以初步得出结论是:0,0,0,0,1。

3.进一步分析

透过runtime源码分析到,其实类对象也可以使用这两个方法的,其中的奥妙如下:

+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}

+ (Class)superclass {
    return self->superclass;
}

- (Class)superclass {
    return [self class]->superclass;
}

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

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

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

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

从runtime源码中我们可以看到类对象和实例对象分别有对应的+ (BOOL)isKindOfClass:(Class)cls- (BOOL)isKindOfClass:(Class)cls方法。所以,并不是我们一开始猜想的那样。

3.1 + (BOOL)isKindOfClass:(Class)cls分析

当调用对象为类对象的时候,我们可以发现其底层是一个循环遍历判断。
我们了解到,当A对象为NSObject对象时,其isa指针指向的是NSObject元类(Meta),所以第一次循环元类和类对象肯定是不相等的。接下来第二次循环是
元类对象的superclass指向的是NSObject本身,所以第二次循环是返回True的。关于isasuperclass之间的指向关系我们可以通过下面这张图一览无遗:

isa和superclass指向.png

3.2 + (BOOL)isMemberOfClass:(Class)cls分析

通过上面这张图我们可以清晰看到,类方法中只是简单的做了一个isa指针和class之间的比较。所以,无论是NSObject的isa还是继承自NSObject的子类的isa都是指向A对象的元类,元类是类本身肯定是不一样的。

4.再来逐个分析

//问题1: 在3.1中已经说明,有两次循环,第二次会相等
BOOL result1 = [[NSObject class] isKindOfClass:[NSObject class]];
//问题2:类方法是直接拿A对象的isa比较,元类和类不同,所以不相等
BOOL result2 = [[NSObject class] isMemberOfClass:[NSObject class]];
//问题3:逐次循环分析
//第一次:Person->isa = Person Meta != Person
//第二次:Person Meta -> superclass = NSObject Meta != Person
//第三次:我们看到左边A对象的superclass会一直沿着关系图往上走,一直到nil都不会相等
BOOL result3 = [[Person class] isKindOfClass:[Person class]];
//和问题2相同也不会相等
BOOL result4 = [[Person class] isMemberOfClass:[Person class]];

所以综合上述,正确的答案应该是:1,0,0,0,1。
感谢各位大佬们,欢迎点赞。

你可能感兴趣的:(理解isKindOfClass和isMemberOfClass的区别)