举例子🌰
首先看一下如下代码的执行结果
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; //
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; //
BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]]; //
BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]]; //
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; //
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; //
BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]]; //
BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]]; //
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
执行结果如下:
isKindOfClass源码分析
到Apple open source下载781源码,并配置成可编译的源码
在可编译的源码中找到isKindOfClass
的实现,我们发现有两个:
类方法
+ (BOOL)isKindOfClass:(Class)cls {
// 类 vs 元类
// 根元类 vs NSObject
// NSObject vs NSObject
// LGPerson vs 元类 (根元类) (NSObject)
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
此函数是通过self
的isa
打到当前类的元类
,判断元类
是存在,如果存在就比较元类
和当前类
是否相同,相同返回YES
,不同,再打到元类的父类,再进行比较。此函数用来判断元类是否相同。
实例方法
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
此函数是通过[self class]
拿到当前对象的类和传进来的类cls
进行比较,如果相同,返回YES
,如果不同,到当前对象的类的父类,再比较。此函数用来判断对象是否属于某个类或者其子类.
isMemberOfClass源码分析
同样的,有类方法和实例方法
类方法
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
此函数用于判断元类是否相同
实例方法
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
此函数用来判断对象是否属于某个类
那么当类或者对象在调用isKindOfClass
和isMemberOfClass
时,真的会来到上面介绍的这些方法吗?
下面我们执行一下代码,并打下断点:
但是并没有走到下面这两个方法中的任何一个
事实上,通过alloc
的流程分析我们可以类比到这里,LLVM
对isKindOfClass
肯定进行了优化,使得isKindOfClass
的调用被hook了。
通过在底层源码的全局搜索我们发现,还存在一个名为objc_opt_isKindOfClass
的c语言函数,isKindOfClass
的调用被hook到了objc_opt_isKindOfClass
。
objc_opt_isKindOfClass
实现如下:
打个断点调试一下:
因为isKindOfClass的类方法和对象方法都是用传入的cls依次和self->isa()的继承链作对比,逻辑是一样的,所以优化后可以提高性能。
例题讲解
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
调用是类方法
isKindOfClass
,[NSObject class]是类NSObject
,虽然NSObject和根元类不相同,但根元类继承自NSObject,所以结果为YES
;
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
[NSObject class]的元类和NSObject显然不相同,所以结果为
NO
;
BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];
[LGPerson class]的元类和根元类的父类NSObject和LGPerson都不相同,结果为
NO
;
BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];
[LGPerson class]的元素和LGPerson不相同,结果为
NO
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
[NSObject alloc]对象的类是NSObject,和NSObject相同,结果为
YES
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
[NSObject alloc]的类和NSObject相同,结果为
YES
BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];
[LGPerson alloc]对象的类LGPerson和LGPerson相同,结果为
YES
BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];
[LGPerson alloc]对象的类和LGPerson相同,结果为
YES