首先要用到这么一张图
什么是内省?
在计算机科学中,内省是指计算机程序在运行时(Runtime)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查。 不应该将内省和反射混淆。
相对于内省,反射更进一步,是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。
内省的几个方法
isMemberOfClass
//对象是否是某个类型的 对象
+isMemberOfClass 类方法是直接判断当前类的isa指向 (也就是当前类的元类) 和对比类是否相等。
-isMemberOfClass 对象方法是直接判断 [self class] (当前类) 和对比类是否相等。
isKindOfClass
//对象是否是某个类型或某个类型子类的 对象
+isKindOfClass 类方法是从当前类的isa指向 (也就是当前类的元类) 开始,沿着 superclass 继承链查找判断和对比类是否相等。
-isKindOfClass 对象方法是从 [self class] (当前类) 开始,沿着 superclass 继承链查找判断和对比类是否相等。
isSubclassOfClass
//某个类对象 是否是另一个类型的子类
isAncestorOfObject
//某个类对象 是否是另一个类型的父类
respondsToSelector
//是否能响应某个方法
conformsToProtocol
//是否遵循某个协议
isKindOfClass 与 isMemberOfClass比较代码
@interface Sark : NSObject
@end
@implementation Sark
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];
BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];
NSLog(@"%d %d %d %d", res1, res2, res3, res4);
BOOL res5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL res6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL res7 = [(id)[Sark alloc] isKindOfClass:[Sark class]];
BOOL res8 = [(id)[Sark alloc] isMemberOfClass:[Sark class]];
NSLog(@"%d %d %d %d", res5, res6, res7, res8);
}
return 0;
}
//1 0 0 0
//1 1 1 1
-我们先看看isKindOfClass
-
+isKindOfClass
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
-
-isKindOfClass源码
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
调试最终的代码并不会运行到此处,这是因为在编译时系统经过编译优化,所以最终会运行到objc_opt_isKindOfClass
方法
-
objc_opt_isKindOfClass 源码
// 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->superclass) {
if (tcls == otherClass) return YES;
}
return NO;
}
#endif
return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}
从源码可以看到:
- 如果调用者obj是类类型,我们知道类的isa指向该类的元类,所以这时会走元类
meta class
的继承链条进行查找判断,先判断class是否等于meta class
,不等就继续循环判断是否等于super class
,不等再继续取,如此循环下去。- 如果调用者obj是对象,那么最终会获取该对象的isa然后走该对象的类的继承链进行查找判断
+isKindOfClass
-
[NSObject class]执行完之后调用isKindOfClass
第一次判断先判断[NSObject class]
和 [NSObject class] 的meta class
是否相等,从图上我们也可以看出,[NSObject class]的meta class
与[NSObject class]
不等;
第二次循环判断[NSObject class]
与meta class的superclass
是否相等。还是从那张图上面我们可以看到:Root class(meta) 的superclass
就是 Root class(class)
,也就是[NSObject class]
。所以第二次循环相等,于是第一行res1输出应该为YES。如下图:
-
[Sark class]执行完之后调用isKindOfClass;
第一次for
循环,Sark的Meta Class
与[Sark class]
不等;
第二次for循环
,Sark
Meta Class的super class
指向的是 Root class(meta)
, 和 [Sark class]
不相等;
第三次for循环,Root class(meta)
的super class
指向的是Root class(class)
,也就是NSObject
本身,和 [Sark class]
不相等。
第四次循环,Root class(class)
的 super class
指向 nil
, 和 [Sark class]
不相等。四次循环之后,退出循环,所以第三行的res3
输出为NO。
-isKindOfClass
如果把这里的Sark改成它的实例对象,[sark isKindOfClass:[Sark class]
,那么此时就应该输出YES
了。
此处描述错误
因为在isKindOfClass
函数中,判断sark的meta class
是自己的元类Sark
,第一次for循环就能输出YES
了。
从-isKindOfClass源码
我们可以看到,对象方法的 for循环 初始值 变成了 [self class]
,也就是从当前类开始找superclass继承链。
所以 [(id)[NSObject alloc] isKindOfClass:[NSObject class]] 和 [(id)[sark alloc] isKindOfClass:[sark class]] 都为 YES。
-接着看看isMemberOfClass
isMemberOfClass源码
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
+isMemberOfClass
的源码实现是拿到自己的isa指针
(也就是当前类的元类) 和自己比较,是否相等。
res2[NSObject class]的isa
指向 [NSObject class] 的 Meta Class
,所以和 [NSObject class]
不相等;
res4,[Sark class]的isa
指向[Sark class]的Meta Class
,和[Sark class]
也不等;
所以res2
和res4
都输出NO。
-isMemberOfClass
对象方法更是简单了,直接就是判断当前类和传入类是否相等。所以res6
和res8
都输出YES。