538 字
3 分钟
isKindOfClass的底层实现
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);思考一下,会输出什么?
结果:
2021-06-27 08:29:10.567002+0800 IsKindOf[62355:691675] Class 1 0 0 02021-06-27 08:29:10.567836+0800 IsKindOf[62355:691675] Instacne 1 1 1 1如果仅从字面上去理解代码,那么你的答案应该会是不一样的的。我们从源码层面来理解一下吧,源码不长,很容易理解。
一、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;}1.1 流程图-Class

- [NSObject class] 即
RootClassRootClass-(ISA)>RootMetaClass-(superClass)>RootClass- true
- [RYModel class]
[RYModel class]-(ISA)>RYModelMetaClass-(superClass)>RootMetaClass-(superClass)>RootClass-(superClass)>nil- false
1.2 流程图-Instance

- NSObjectInstance
NSObjectInstance-(class)>RootClass- true
- RYModelInstance
RYModelInstance-(class)>RYModelClass- true
二、isMemberOfClass
+ (BOOL)isMemberOfClass:(Class)cls { return self->ISA() == cls;}
- (BOOL)isMemberOfClass:(Class)cls { return [self class] == cls;}这里就很简单了,就不展开说了。
三、你以为这就完了?
如果你看到这里觉得没啥问题?那就有问题了。。。
我们运行下OC源码,两个断点。

运行之后发现 +/- (Bool)isKindOfClass:(Class)cls 居然根本没有调用。
3.1 汇编
通过断点汇编,我们在调用 isKindOfClass 的地方发现了这样的指令 objc_opt_isKindOfClass
-> 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_isKindOfClass3.2 objc_opt_isKindOfClass
// Calls [obj isKindOfClass]BOOLobjc_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 的方法都走到了这里。

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