直接看下面的代码会打印什么内容
先看下 -(Class)class 和 +(Class)class方法的实现
可以看出类对象调用class方法就是返回自己本身,所以类对象不管调用多少次class都是返回的当前类对象
实例对象调用class是返回该实例对象isa所指向的对象也就是类对象,但是继续调用class就变成了上面的类对象调用class,返回的还是类对象
所以想得到元类对象,可以使用上面的object_getClass来获取,参数是传入类对象,因为类对象的isa指向的是元类对象,object_getClass([NSObject class])
所有的元类对象的isa是指向的NSObject,下面的图可以看出来,可以这样获取 object_getClass(object_getClass([NSObject class]))
知道这些关系后我们再看下isKindOfClass、isMemberOfClass这两个方法的实现
再次说下object_getClass这个方法,该方法返回的是传入参数的isa所指向的对象,如果传入的是实例参数,那么返回的就是该实例对象的类对象,如果传入的参数是类对象,那么返回的是类对象的元类对象,由此可知如果self是实例对象,那么 [self class] 和object_getClass(self)是等价的,都是返回的类对象
从这两个方法的实现可以看出
isMemberOfClass
实例方法:直接获取当前调用者的self的类对象([self class])与传入的类对象参数(cls)进行比较,相同则返回true,需要注意的是当前调用者是实例对象,[self class]返回的是类对象
类方法:直接获取当前调用者self的isa所指向的对象也就是元类对象([object_getClass((id)self)])与传入的参数(cls)进行比较,相同则返回true,需要注意的是当前调用者是类对象,([object_getClass((id)self)])返回的是当前类对象的isa所指向的对象,也就是元类对象
isKindOfClass
实例方法:循环遍历当前调用者self的类对象、父类对象、祖父类对象(Classtcls = [selfclass]; tcls; tcls = tcls->superclass)一直到NSObject,与传入的类对象参数cls进行比较,相同则返回true
类方法:循环遍历当前调用者self的isa所指向的类对象、父类对象、祖父类对象(Classtcls =object_getClass((id)self); tcls; tcls = tcls->superclass)一直到NSObject,与传入的类对象参数cls进行比较,相同则返回true,需要注意的是当前调用者是类对象,([object_getClass((id)self)])返回的是当前类对象的isa所指向的对象,也就是元类对象
在看代码前先看下isa和superclass以及rootclass在OC对象之间所担任的联系图片
再看上面的第一句代码
BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
由于[NSObject class]返回的是类对象NSObject,所以调用的是+方法,所以调用者是NSObject这个类对象,而传入的参数也是NSObject类对象,但方法里面还要循环获取调用者NSObject的isa所指向的对象(object_getClass方法是获取当前对象的isa所指向的对象),而NSObject的isa指向的是NSObject元类对象,所以第一次循环不相等,进入第二次循环,NSObject元类对象的父类是NSObject类对象,这次就相等了
再看第二句代码
BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
通过第一句代码的分析可以得知NSObject的isa指向的是NSObject元类对象,元类对象不等于类对象NSObject,所以返回false,如果要返回true,可以传入NSObject的元类对象,可以这样写
BOOL res2 = [[NSObject class] isMemberOfClass:object_getClass([NSObject class])];
再看第三句代码
BOOL res3 = [[WPPerson class] isKindOfClass:[WPPerson class]];
WPPerson本身就是类对象,而传入的参数也是类对象,但isKindOfClass方法内部对调用者也就是WPPerson类对象又进行了一次object_getClass操作,也就是从WPPerson的元类对象开始比较,一直找到NSObject也没有找到相等的,所以返回false,如果要返回true,也需要传入WPPerson的元类对象
BOOL res3 = [WPPerson isKindOfClass:object_getClass([WPPerson class])];
再看第四局代码
BOOL res4 = [[WPPerson class] isMemberOfClass:[WPPerson class]];
WPPerson本身就是类对象,而传入的参数也是类对象,但isMemberOfClass方法内部对调用者也就是WPPerson类对象又进行了一次object_getClass操作,也就是将WPPerson的元类对象和传入的WPPerson类对象参数进行比较,所以返回false,如果要返回true,也需要传入WPPerson的元类对象
BOOL res4 = [[WPPerson class] isMemberOfClass:object_getClass([WPPerson class])];
再看下对象方法
可以看出调用者都是实例对象self,isMemberOfClass和isKindOfClass都会对self进行一次class操作,也就是获取当前self的类对象,而传入的参数又恰好都是类对象,所以会出现这种结果,第一行和第二行代码的类对象不相同,所以第二行直接返回的false,但是第一行isKindOfClass会一直查找self类对象的父类对象,一直到NSObject,所以找到最后才发现相同,所以返回的true