OC中 isKindOfClass 与 isMemberOfClass 的本质

508 阅读1分钟

简单使用

Person继承自NSObject

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
        Person *person = [[Person alloc] init];
        
        BOOL res1 = [obj isKindOfClass:[NSObject class]];   // YES
        BOOL res2 = [obj isMemberOfClass:[NSObject class]]; // YES
        BOOL res3 = [person isKindOfClass:[Person class]];  // YES
        BOOL res4 = [person isMemberOfClass:[Person class]]; // YES
        
        NSLog(@"%d %d %d %d", res1, res2, res3, res4);
        
        BOOL res5 = [[NSObject class] isKindOfClass:[NSObject class]];  // YES
        BOOL res6 = [[NSObject class] isMemberOfClass:[NSObject class]];  // NO
        BOOL res7 = [[Person class] isKindOfClass:[Person class]];  // NO
        BOOL res8 = [[Person class] isMemberOfClass:[Person class]]; // NO
        
        NSLog(@"%d %d %d %d", res5, res6, res7, res8);
    }
    return 0;
}

打印结果:
2020-08-28 17:26:00.062645+0800 LearningRuntime[13636:221035] 1 1 1 1
2020-08-28 17:26:00.064095+0800 LearningRuntime[13636:221035] 1 0 0 0

如上,若打印结果和你预期的一致,那恭喜你已经掌握了两者的本质,不需要再继续往下看了。

分析

想要理解打印的结果,最直接的方法就是看下isKindOfClassisMemberOfClass的底层实现。在runtime源码的NSObject.mm文件中可以找到对应方法的实现。如下:

// 类方法
+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}
// 实例方法
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}
// 类方法
+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); 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;
}

由源码可知,isKindOfClassisMemberOfClass 实例方法是拿类对象进行比较,类方法是拿元类对象进行比较。 所以上面的打印结果不难得出。

注意点:NSObject元类对象的superclass指针指向NSObject类对象。这就是 res5 结果为YES的原因。

图: avatar

参考

  1. runtime源码
  2. MJ 底层分析