苹果官方描述:
1. Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class.
- (BOOL)isKindOfClass:(Class)aClass;
2. Returns a Boolean value that indicates whether the receiver is an instance of a given class.
- (BOOL)isMemberOfClass:(Class)aClass;
isa、superClass走位图
在进一步探索前我们要先通过下图了解OC中的:实例对象(instance)、类对象(class)、元类对象(meta)之间的关系
isa简单概括为:instance的isa-> class,class的isa-> meta,meta的isa->根元类,根元类的isa->指向根元类自己
superClass简单概括为:1、class的superClass指向父类,Root class的superClass为nil;2、元类的superClass指向父元类,根元类的superClass指向Root class。
Class相关源码
结合这些Class相关的源码和isa走位图可以更加清晰的理解isKindOfClass
、isMemberOfClass
的实现
//参数`id obj`,中的obj包含实例对象(instance)、类对象(class)、元类对象(meta)
//obj是实例对象(instance) 返回结果是类对象(class)
//obj是类对象(class)返回的结果是元类对象(meta)
//obj是元类对象(meta)返回的结果是根元类
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
+ (Class)superclass {
return self->superclass;
}
- (Class)superclass {
return [self class]->superclass;
}
isKindOfClass、isMemberOfClass源码实现
isKindOfClass、isMemberOfClass两个方法的参数cls可以是类对象(class)、元类对象(meta)
-
isKindOfClass:
类方法:self可以是类对象(class)、元类对象(meta)
1、获取类对象的isa(元类对象)给tcls
2、如果tcls存在,判断tcls与cls是否相等,相等返回YES,不相等继续对比tcls的superclass。
3、tcls = tcls->superclass,一直找到根元类,如果根元类与cls也不相等,则tcls = Root class(meta)->superclass,既tcls = Root class。
4、如果Root class与cls也不相等,tcls = Root class ->superclass,既tcls = nil,退出循环,返回NO。
通过分析发现+ (BOOL)isKindOfClass:(Class)cls
的参数传入如果是除了根类的其他类对象,则实际是用元类对象和类对象比较,一定会返回NO。+ (BOOL)isKindOfClass:(Class)cls { for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; }
实例方法:self是类的实例对象,由上面的Class相关源码
- (Class)class
可知,[self class]
的结果是实例对象的isa指向的类对象,既 self对应的类,tcls = 类对象(class)。
如果tcls与cls不相等,则判断tcls->superclass与cls是否相等,直到tcls = Root Class-> superclass,既tcls = nil退出循环。
通过分析发现这个循环中并没有获取到对象的元类进行比较,所以实例对象调用isKindOfClass:
方法时如果参数传入的是元类,则一定返回NO。- (BOOL)isKindOfClass:(Class)cls { for (Class tcls = [self class]; tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; }
1、通过对上面isKindOfClass
类方法、实例方法的分析发现,由于Root class-> superclass是nil,根元类的superclass是Root class,所以不会进行死循环。
2、判断一个对象和其指定的类之间的关系:实例对象-类对象,类对象-元类,(由于跟元类的superclass指向根类,所以这是个特殊情况,可以进类对象-类对象、元类-元类)
3、验证了官方描述:isKindOfClass
用来判断一个对象是否是指定类或者该类的子类的实例对象。从这里也反应了类是其元类的对象,所以称为类对象
isKindOfClass:
的实际调用
当进入断点调试时发现isKindOfClass:
并不会进入上面分析的源码,在isKindOfClass:
断点,按住control,点击↓
(Xcode调试step into按钮:step into instruction (hold control)),会进入汇编调用:
object-study`objc_opt_isKindOfClass:
-> 0x100001884 <+0>: jmpq *0x17a6(%rip) ; (void *)0x00000001000018e4
实际调用了objc_opt_isKindOfClass
,这是因为llvm编译器对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);
}
重点内容:
//获取isa,实例对象的isa是类对象,类对象的isa是元类。
//这里优化了+isKindOfClass:和-isKindOfClass:
//等价于+isKindOfClass:方法中的Class tcls = self->ISA()
//等价于-isKindOfClass:方法中的Class tcls = [self class]
Class cls = obj->getIsa();
if (fastpath(!cls->hasCustomCore())) {
//循环继承链,对比otherClass是否在继承链上
for (Class tcls = cls; tcls; tcls = tcls->superclass) {
if (tcls == otherClass) return YES;
}
return NO;
}
分析发现结果和我们上面对+isKindOfClass:
和-isKindOfClass:
分析的一致
-
isMemberOfClass:
类方法:self可以是类对象(class)、元类对象(meta)
1、self是类对象,则self->ISA()
是其元类。
2、self是元类对象,则self->ISA()
是根元类。
那么self->ISA() == cls
就是判断一个类对象或元类对象是否是指定类的实例对象。+ (BOOL)isMemberOfClass:(Class)cls { return self->ISA() == cls; }
实例方法:self是类的实例对象,由上面的Class相关源码
- (Class)class
可知,[self class]
的结果是实例对象的isa指向的类对象,既self对应的类。那么[self class] == cls
就是判断实例对象是否是类对象的实例对象。- (BOOL)isMemberOfClass:(Class)cls { return [self class] == cls; }
验证了官方描述:isMemberOfClass
用来判断一个对象是否是指定类的实例对象。从这里也反应了类是其元类的对象,元类是根元类的对象,和isa走位图吻合
isKindOfClass
和isMemberOfClass
相同点都是判断对象和其指定类的关系,不同点是isKindOfClass
包含了继承关系,可以判断是否是其类的子类对象,isMemberOfClass
不包含继承关系。
代码验证
#import
#import
@interface STPerson : NSObject
@end
@implementation STPerson
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *rootObj = [NSObject alloc];//实例对象
//[rootObj class]和[NSObject class]是相同的
//Class rootClass = [NSObject class];
Class rootClass = [rootObj class];//Root class 类对象
Class rootMeta = object_getClass(rootClass); //根元类
NSLog(@"【[rootObj class]=[NSObject class]】%d",[rootObj class]==[NSObject class]); //1
NSLog(@"【rootMeta is Meta】 %d",class_isMetaClass(rootMeta)); //1
STPerson *person = [STPerson alloc];//STPerson 实例对象
Class personClass = [person class];//STPerson 类对象
Class personMeta = object_getClass(personClass); //STPerson 元类
NSLog(@"【personMeta is Meta】%d",class_isMetaClass(personMeta)); //1
NSLog(@"***** + (BOOL)isKindOfClass:(Class)cls ******");
NSLog(@"【Root class-Root class】 %d",[rootClass isKindOfClass:rootClass]);
NSLog(@"【Root Meta-Root Meta】 %d",[rootMeta isKindOfClass:rootMeta]);
NSLog(@"【Root class-Root Meta】 %d",[rootClass isKindOfClass:rootMeta]);
NSLog(@"【personClass-Root class】 %d",[personClass isKindOfClass:rootClass]);
NSLog(@"【personClass-personClass】 %d",[personClass isKindOfClass:personClass]);
NSLog(@"【personMeta-personMeta】 %d",[personMeta isKindOfClass:personMeta]);
NSLog(@"【personClass-personMeta】 %d",[personClass isKindOfClass:personMeta]);
NSLog(@"【personMeta-personClass】 %d",[personClass isKindOfClass:personClass]);
//+ (BOOL)isKindOfClass:(Class)cls的打印结果是:1、1、1、1、0、0、1、0
NSLog(@"***** -(BOOL)isKindOfClass:(Class)cls *****");
NSLog(@"【rootObj-rootMeta】 %d",[rootObj isKindOfClass:rootMeta]);
NSLog(@"【rootObj-rootClass】 %d",[rootObj isKindOfClass:rootClass]);
NSLog(@"【person-rootMeta】 %d",[person isKindOfClass:rootMeta]);
NSLog(@"【person-personMeta】 %d",[person isKindOfClass:personMeta]);
NSLog(@"【person-personClass】 %d",[person isKindOfClass:personClass]);
NSLog(@"【person-rootClass】 %d",[person isKindOfClass:rootClass]);
//- (BOOL)isKindOfClass:(Class)cls的打印结果是:0、1、0、0、1、1
NSLog(@"***** + (BOOL)isMemberOfClass:(Class)cls *****");
NSLog(@"【Root Meta-Root Meta】 %d",[rootMeta isMemberOfClass:rootMeta]);
NSLog(@"【personMeta-Root Meta】 %d",[personMeta isMemberOfClass:rootMeta]);
NSLog(@"【rootClass-rootClass】 %d",[rootClass isMemberOfClass:rootClass]);
NSLog(@"【rootClass-rootMeta】 %d",[rootClass isMemberOfClass:rootMeta]);
NSLog(@"【personClass-Root Meta】 %d",[personClass isMemberOfClass:rootMeta]);
NSLog(@"【personClass-personMeta】 %d",[personClass isMemberOfClass:personMeta]);
//+ (BOOL)isMemberOfClass:(Class)cls的打印结果是:1、1、0、1、0、1
NSLog(@"***** - (BOOL)isMemberOfClass:(Class)cls *****");
NSLog(@"【rootObj-rootMeta】 %d",[rootObj isMemberOfClass:rootMeta]);
NSLog(@"【rootObj-rootClass】 %d",[rootObj isMemberOfClass:rootClass]);
NSLog(@"【person-rootMeta】 %d",[person isMemberOfClass:rootMeta]);
NSLog(@"【person-rootClass】 %d",[person isMemberOfClass:rootClass]);
NSLog(@"【person-personClass】 %d",[person isMemberOfClass:personClass]);
NSLog(@"【person-personMeta】 %d",[person isMemberOfClass:personMeta]);
//- (BOOL)isMemberOfClass:(Class)cls的打印结果是:0、1、0、0、1、0
}
return 0;
}
如果有歧义、错误的地方,欢迎留言指出,以免误导大家。