[toc] 开发中经常会使用 `isKindOfClass` 判断对象是否是某个类或者是其父类(整个继承链上的类),很少会用到 `isMemberOfClass` ,本文就从源码层面来探索他们之间的关系。 ## 一、准备 ```objectivec // DZPerson继承自NSObject @interface DZPerson : NSObject @end #import <Foundation/Foundation.h> #import "DZPerson.h" #import <objc/runtime.h> int main(int argc, const char * argv[]) { @autoreleasepool { BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; // 1 BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; // 0 BOOL re3 = [(id)[DZPerson class] isKindOfClass:[DZPerson class]]; // 0 BOOL re4 = [(id)[DZPerson class] isMemberOfClass:[DZPerson class]]; // 0 NSLog(@"\n re1:%hhd re2:%hhd re3:%hhd re4:%hhd",re1,re2,re3,re4); BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; // 1 BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; // 1 BOOL re7 = [(id)[DZPerson alloc] isKindOfClass:[DZPerson class]]; // 1 BOOL re8 = [(id)[DZPerson alloc] isMemberOfClass:[DZPerson class]]; // 1 NSLog(@"\n re5:%hhd re6:%hhd re7:%hhd re8:%hhd",re5,re6,re7,re8); } return 0; } /** 打印: re1:1 re2:0 re3:0 re4:0 re5:1 re6:1 re7:1 re8:1 */ ``` ## 二、源码分析 上述代码其实调用了四个方法: >类方法: +isKindOfClass +isMemberOfClass >对象方法: -isKindOfClass -isMemberOfClass ### 1. +isKindOfClass 源码 ```objectivec + (BOOL)isKindOfClass:(Class)cls { for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; } Class object_getClass(id obj) { if (obj) return obj->getIsa(); else return Nil; } ``` - **Class tcls = object_getClass((id)self);** 从源码可以看到,`self` 是类本身,`object_getClass((id)self)` 则是获取 `isa`,而 `isa` 是指向`元类`的,所以 `tcls` 实际上是当前类的元类。 - **for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass)** - for循环实际上就是从`当前类的元类`开始,沿着继承链中的 `superclass` 一直向上循环,在如下 `isa`指向图 中标注部分,`NSObject`元类 的父类是 `NSObject`。所以在第二次循环的时候,`NSObject`元类 的 `superclass` 是本身`NSObject`。 - 但是 `DZPerson`元类 的继承链是`DZPerson元类 -> NSObject元类 -> NSObject`,所以在 `DZPerson`元类 的继承链上永远不会有自身`DZPerson`。 - 因此 `[(id)[NSObject class] isKindOfClass:[NSObject class]] = YES` ,而 `[(id)[DZPerson class] isKindOfClass:[DZPerson class]] == NO`。 ![](https://img.kancloud.cn/73/67/736752e0e4d381e892f08b1d0a359dcf_1200x520.png) ### 2. +isMemberOfClass 源码 ```objectivec + (BOOL)isMemberOfClass:(Class)cls { return object_getClass((id)self) == cls; } ``` - 从源码中可以看到,代码是直接判断当前`类的元类`是否等于传入类。 - 所以 `[(id)[NSObject class] isMemberOfClass:[NSObject class]]` 和 `[(id)[DZPerson class] isMemberOfClass:[DZPerson class]]`中,`NSObject`元类 不等于 `NSObject`,`DZPerson`元类 也不等于 `DZPerson`,结果自然都是 `NO`。 ### 3. -isKindOfClass 源码 ```objectivec - (BOOL)isKindOfClass:(Class)cls { for (Class tcls = [self class]; tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; } ``` 我们可以看到,对象方法的 for循环 初始值 变成了 [self class],也就是从当前类开始找superclass继承链。 所以 [(id)[NSObject alloc] isKindOfClass:[NSObject class]] 和 [(id)[DZPerson alloc] isKindOfClass:[DZPerson class]] 都为 YES。 ### 4. -isMemberOfClass 源码 ```objectivec - (BOOL)isMemberOfClass:(Class)cls { return [self class] == cls; } ``` - `-isMemberOfClass` 对象方法更是简单了,直接就是判断`当前类`和传入类是否相等。 - `[(id)[NSObject alloc] isMemberOfClass:[NSObject class]]` 和 `[(id)[DZPerson alloc] isMemberOfClass:[DZPerson class]]` 自然都是 `YES`。 ## 三、总结 - `+isKindOfClass` 类方法是从`当前类的isa指向` (也就是当前类的元类) 开始,沿着 `superclass` 继承链查找判断和对比类是否相等。 - `-isKindOfClass` 对象方法是从 `[self class]` (当前类) 开始,沿着 `superclass` 继承链查找判断和对比类是否相等。 - `+isMemberOfClass` 类方法是直接判断当前`类的isa指向` (也就是当前类的元类) 和对比类是否相等。 - `-isMemberOfClass` 对象方法是直接判断 `[self class]` (当前类) 和对比类是否相等。