iOS 底层分析

iOS isKindOfClass、isMemberOfClas

2019-11-26  本文已影响0人  Good_Citizen

直接看下面的代码会打印什么内容

先看下 -(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所指向的对象,也就是元类对象

在看代码前先看下isasuperclass以及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

上一篇 下一篇

猜你喜欢

热点阅读