# 08.isKindOfClass的底层实现

```cpp
BOOL result1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL result2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL result3 = [[RYModel class] isKindOfClass:[RYModel class]];
BOOL result4 = [[RYModel class] isMemberOfClass:[RYModel class]];

NSLog(@"Class\n %hhd \n %hhd \n %hhd \n %hhd", result1, result2, result3, result4);

BOOL result5 = [[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL result6 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL result7 = [[RYModel alloc] isKindOfClass:[RYModel class]];
BOOL result8 = [[RYModel alloc] isMemberOfClass:[RYModel class]];

NSLog(@"Instacne\n %hhd \n %hhd \n %hhd \n %hhd", result5, result6, result7, result8);
```

思考一下，会输出什么？

结果：

```cpp
2021-06-27 08:29:10.567002+0800 IsKindOf[62355:691675] Class
 1 
 0 
 0 
 0
2021-06-27 08:29:10.567836+0800 IsKindOf[62355:691675] Instacne
 1 
 1 
 1 
 1
```

如果仅从字面上去理解代码，那么你的答案应该会是不一样的的。我们从源码层面来理解一下吧，源码不长，很容易理解。

## 一、isKindOfClass

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

### 1.1 流程图-Class

![Class-isKindOfClass](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F5e5399bb81d101d165bb4832cbcfcb3640676cde.png?generation=1624756609805584\&alt=media)

* \[NSObject class] 即 `RootClass`
  * `RootClass` -(ISA)> `RootMetaClass` -(superClass)> `RootClass`
  * true
* \[RYModel class]
  * `[RYModel class]` -(ISA)> `RYModelMetaClass` -(superClass)> `RootMetaClass` -(superClass)> `RootClass` -(superClass)> `nil`
  * false

### 1.2 流程图-Instance

![Instance-isKindeOfClass](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fac5879c9a711763ad925a51c52884a8f22960cb0.png?generation=1624756608712419\&alt=media)

* NSObjectInstance
  * `NSObjectInstance` -(class)> `RootClass`
  * true
* RYModelInstance
  * `RYModelInstance` -(class)> `RYModelClass`
  * true

## 二、isMemberOfClass

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

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

这里就很简单了，就不展开说了。

## 三、你以为这就完了？

> 如果你看到这里觉得没啥问题？那就有问题了。。。

我们运行下OC源码，两个断点。

![IsKindofClass01](https://github.com/RyukieSama/RyukieDevGitBook/tree/3fa18668f891626268e2f78624a16b279bba216e/iOS/%E5%BA%95%E5%B1%82%E7%9F%A5%E8%AF%86%E6%A2%B3%E7%90%86/Images/IsKindofClass01.png)

运行之后发现 `+/- (Bool)isKindOfClass:(Class)cls` 居然根本没有调用。

### 3.1 汇编

通过断点汇编，我们在调用 `isKindOfClass` 的地方发现了这样的指令 `objc_opt_isKindOfClass`

```cpp
->  0x10000381c <+332>: mov    rdi, qword ptr [rip + 0x4f7d] ; (void *)0x0000000100008808: RYModel
    0x100003823 <+339>: call   0x100003b42               ; symbol stub for: objc_opt_class
    0x100003828 <+344>: mov    rbx, rax
    0x10000382b <+347>: mov    rdi, qword ptr [rip + 0x4f6e] ; (void *)0x0000000100008808: RYModel
    0x100003832 <+354>: call   0x100003b42               ; symbol stub for: objc_opt_class
    0x100003837 <+359>: mov    rdi, rbx
    0x10000383a <+362>: mov    rsi, rax
    0x10000383d <+365>: call   0x100003b48               ; symbol stub for: objc_opt_isKindOfClass
```

### 3.2 objc\_opt\_isKindOfClass

```cpp
// Calls [obj 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);
}
```

在这里下断点，我们发现的确进到了这里。并且 `Class` 和 `Instance` 的方法都走到了这里。

![IsKindOfClass02](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F641331546d5f45409e5b838d20fbb59a6e722813.png?generation=1624758760634212\&alt=media)

编译器对这里进行的优化，用更高效的 `objc_opt_isKindOfClass` 代替了原有的方法。

## 四、参考

> [slowpath & fastpath](https://ryukiedev.gitbook.io/wiki/ios/di-ceng/09.slowpath-and-fastpath)
