关于isKindOfClass和isMemberOfClass的一点理解

127 阅读2分钟

isKindOfClass

以前了解的isKindOfClass

源码实现如下:

+ (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;
}

在工程中测试isKindOfClass的功能按照这边的源码来解析也是对的,但后面再objc源码中打断点的时候,突然发现了这边的断点竟然没有进,通过反汇编查看了调用isKindOfClass真正进的方法是objc_opt_isKindOfClass,骗了我好些年。。

分析objc_opt_isKindOfClass源码

源码如下,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);
}

源码可以看出,在非__OBJC2__环境下还是会走之前的isKindOfClass的类方法和实例方法

举几个个人认为比较经典的例子

Person *p = [[Person alloc] init]; 
NSObject *objc = [[NSObject alloc] init];
BOOL res1 = [p isKindOfClass:[Person class]]; //YES
BOOL res2 = [[Person class] isKindOfClass:[Person class]]; //NO
BOOL res3 = [objc isKindOfClass:[NSObject class]]; //YES
BOOL res4 = [[NSObject class] isKindOfClass:[NSObject class]];//YES

image.png

根据上面的图、源码、res1、res4来分析一下

BOOL res1 = [p isKindOfClass:[Person class]];
第一次进循环:

  1. tcls = cls = obj->getIsa();,此时tcls为Person类对象
  2. otherClass的传参是[Person class],也是Person类对象

两者比较结果为YES,直接返回YES

BOOL res4 = [[NSObject class] isKindOfClass:[NSObject class]];

第一次循环:

  1. tcls = cls = obj->getIsa();,传入的obj为NSObject类对象,则tcls为NSObject元类对象
  2. otherClass的传参是[NSObject class],是NSObject类对象
  3. tcls != otherClass,进入下次循环

第二次循环:

  1. tcls = tcls->getSuperclass(),NSObject元类对象的isa指向为NSObject类对象,此时tcls为NSObject类对象
  2. otherClass也为NSObject类对象

两者比较结果为YES,直接返回YES

isMemberOfClass

先看源码

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

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

因为比较简单,就不举例了

类方法是前一个参数的isa指针指向的内容与后一个参数进行比较

示例方法是前一个参数的类对象与后一个参数进行比较