iOS底层学习-isKindOfClass和isMemberOfClass面试题

isKindOfClassisMemberOfClass面试题

我们首先来看一段面试题代码,大家可以想一下re1re8分别输出什么

image.png

在这之前我们需要了解isKindOfClassisMemberOfClass

isKindOfClass:

returns YES if the receiver is an instance of the specified class or an instance of any class that inherits from the specified class.

方法调用者是传入的类的实例对象,或者调用者是传入类的继承者链中的类的实例对象,则返回YES。

isMemberOfClass:

returns YES if the receiver is an instance of the specified class.

方法调用者必须是传入的类的实例对象才返回YES。

这里是输出结果:

image.png

那么我们就上面的输出结果结合objc源码来分析一下,找到isKindOfClassisMemberOfClass在源码中的方法实现:

image.png

我们发现了类方法和对象方法实现。平时开发过程中只会接触到对象方法的isKindOfClassisMemberOfClass,但是在NSObject类中还隐式的实现了类方法版本。不只这两个方法,其他NSObject中的对象方法,都有其对应的类方法版本。因为在OC中,类和元类也都是对象。

isKindOfClass类方法

在for循环中的第一个代码块为Class tcls = self->ISA()即找到self的元类;
第二个代码块判断tcls是否存在,(注意,这边存在即直接最后的比较判断,然后再走地第三代码块);
第三个代码块为tcls = tcls->getSuperclass()即找到tcls的父类;
最后的判断if (tcls == cls)
复制代码
  • re1 是比较(id)[NSObject class][NSObject class],我们看isKindOfClass类方法,传进去的clsNSObject,很明显,clsNSObjecttcls也是NSObject,所以返回为YES,即1.

  • re3 是比较(id)[LhkhPerson class][LhkhPerson class],我们继续看isKindOfClass的类方法,传进去的clsLhkhPersonfor循环里面首先拿到LhkhPerson的元类(这里的self就是LhkhPerson),即根元类NSObject(注意这边是一个for循环,后面还是会继续取NSObject父类即nil作比较的),可以得出cls=LhkhPerson肯定和tcls=NSObject,nil不一样,即返回的为NO,也就是0

isKindOfClass对象方法

在for循环中的第一个代码块为Class tcls = [self class]即找到self的类;
第二个代码块判断tcls是否存在,(注意,这边存在即直接最后的比较判断,然后再走地第三代码块);
第三个代码块为tcls = tcls->getSuperclass()即找到tcls的父类;
最后的判断if (tcls == cls)
复制代码
  • re5是比较(id)[NSObject alloc][NSObject class],那我们需要看isKindOfClass对象方法,传进去的clsNSObject,而我们知道[self class](这里的selfNSObject对象)即NSObject,很明显,clsNSObjecttcls也是NSObject,所以返回为YES,即1.

  • re7 是比较(id)[LhkhPerson alloc][LhkhPerson class],我们继续看isKindOfClass的类方法,传进去的clsLhkhPerson,而我们知[self class](这里的self就是LhkhPerson对象)即LhkhPerson,很明显,clsLhkhPersontcls也是LhkhPerson,所以返回为YES,即1.

isMemberOfClass类方法

return self->ISA() == cls;
直接返回self的元类和传进来的cls作比较
复制代码
  • re2是比较(id)[NSObject class][NSObject class],我们看isMemberOfClass的类方法,self->ISA()selfNSObject)即根元类NSObject,很显然类和根元类肯定是不能比较的,所以返回为NO,即0

  • re4是比较(id)[LhkhPerson class][LhkhPerson class],同理得出返回为NO,即0

isMemberOfClass对象方法

return [self class] == cls;
直接返回self的类和传进来的cls作比较
复制代码
  • re6是比较(id)[NSObject alloc][NSObject class],我们看isMemberOfClass的兑现方法,[self class]selfNSObject对象)即类NSObject,很显然都是NSObject,所以返回为YES,即1

  • re8是比较(id)[LhkhPerson alloc][LhkhPerson class],同理得出返回为YES,即1

总结

这个面试题归根结底还是在考察我们对isa走向图类的继承,也就是苹果官方这幅图:

isa流程图.png

补充

我们只是就底层源码对当前输出做了个解释,那么当我们给isKindOfClass添加断点时你会惊奇的发现压根就没来啊

image.png

image.png

我们打开汇编调试可以发现:

image.png
objc_opt_class
objc_opt_isKindOfClass这两个又是些什么啊?我们通过符号埋点得到了这两个方法的实现:

image.png

我们现在使用的objc2,所以直接看objc2判断里面的代码,而objc_opt_class这个方法最终也是返回一个Class,也就是取决于obj,通过下面这行代码:
Class cls = obj->getIsa()

  • obj是对象,那么就取类;
  • obj是类,那么就取元类;

然后就会进入到objc_opt_isKindOfClass这个方法的for循环中,其实就是上面的isKindOfClass相同。

总结

isKindOfClass出现无法进入断点的究其原因就是系统在编译时将isKindOfClass重定向到objc_opt_isKindOfClass这个方法中了,但是有个注意点,objc_opt_classobjc_opt_isKindOfClass是有系统版本要求的。

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享