isKindOf与isMemberOf的原理
本文大约1000字,将会讲述自己关于isKindOf与isMemberOf的原理方面的思考
!!!原创文章,转载请注明来源: pany.fun
# 是什么
面对新的东西,我们第一个思考的问题往往都是——它是什么。
虽然 isKindOf 与 isMemberOf 对于我们来说已经是万分熟悉了,但我们依旧希望 系统而形式 的先来认识它们是什么。
// NSObject.h -> line: 30
@protocol NSObject
- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;
这里首先我们需要注意到,它们是定义在 NSObject协议 中的方法,而不是定义在 NSObject类 中的方法,虽然NSObject类默认实现了它们。
官方文档对于二者的描述
- isKindOfClass:
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.
返回对于 接收者是否是所给类或者所给类的子类的实例 的判断结果
- isMemberOfClass:
Returns a Boolean value that indicates whether the receiver is an instance of a given class.
返回对于 接收者是否是所给类的实例 的判断结果
两个方法异同点如下
- 都能够判断 接收者是否是所给类本身的实例
- isKindOfClass还能够判断接收者是否是所给类的子类的实例,而isMemberOfClass不能
以上内容相对简单,网上搜一搜能找到很多,此文不再多说。
# 为什么
我们的第二个问题——为什么,我们面对新事物往往也会有这样的好奇。
为什么 isKindOfClass 能够进行是否属于子类实例的判断?而isMemberOfClass不能?它们做了什么不一样的事情?
当然,两个不同方法是开发工作的需要,但是这不是我们所想给出的答案,我们更多想知道的是它们是如何去判断的,在判断上又有什么不同。
# 答案
为了理解它们的原理,我们需要先引入一张熟悉的图,如果这张图你不熟悉,请点击这里 或者google
图中Root Class(class)可以理解为NSObject,Root Class(meta)可以理解为NSObject meta
更精准的描述 NSObject: The root class of most Objective-C class hierarchies
isMemberOf 与 isKindOf的判断逻辑,就藏身于这张图中。
isMemberOf:
step1: 找到 isa 指针所指类
step2: 判断 isa所指类 与 所给类 是否相同
isKindOf:
step1: 找到 isa 指针所指类
step2: 判断 isa所指类 与 所给类 是否相同,若不相同 则延该类的继承链(实线)不断向上查询直至nil
两个方法的第一步都是相同的,差别只是在第二步,因为isKindOf多了对于子类的实例的判断,所以也就需要增加继承链的查询。
# 源码
同时因为runtime是开源的,所以我们也可以去查看NSObject源码看是不是这么回事
isMemberOf 源码
- (BOOL)isMemberOfClass:(Class)cls { return [self class] == cls; }
isKindOf 源码
- (BOOL)isKindOfClass:(Class)cls { for (Class tcls = [self class]; tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; }
对比可以发现,isKindOf确实相较isMemberOf多了一个循环,也就是延继承链的查询
# 扩展
在孙源的一篇 神经病院objc runtime入院考试 中有这么一道题目,我们一起以上述原理来看看
(这里为了方便表述,交换了一下几个题目的顺序)
BOOL res1 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; // 原孙源博客中res2
BOOL res2 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; // 原孙源博客中res1
BOOL res3 = [(id)[Sark class] isMemberOfClass:[Sark class]]; // 原孙源博客中res4
BOOL res4 = [(id)[Sark class] isKindOfClass:[Sark class]]; // 原孙源博客中res3
Round 1
接收者为 NSObject ,即图中的 下标A处。取isa,指向 下标B处,并不是NSObject,所以结果为 NO
Round 2
在round 1的基础上继续,已经取到了isa指向 下标B处 且isMemeberOf结果为NO,判断isKindOf接下来需要走继承链,延B的实线走,来到了A处,即NSObject,等于所给类NSObject,所以结果为 YES
Round 3
接收者为 Sark,可以理解为一个继承自NSObject的类,即图中 C 处。取isa指针,指向D,并不是所给的NSObject类,所以结果为NO
Round 4
在round 3的基础上,继续沿D的实线继承链走,经过B、A最终走向nil,始终没有找到所给的Sark类,所以结果为NO
创作不易,转载请注明来源!pany.fun
本文链接:http://pany.fun/post/isKindOf与isMemberOf的原理/