准备工作
isa 走位图
如果想讲明白这两个方法的区别, 那就必须得有这张图. 有了这张图, 大家可以理解的更透彻, 更明白. 实际这张图展示的是 isa
走位 和继承关系, 我习惯叫 isa 走位图
; 我对于这张图的理解有两点;
isa走位
: 对象的 isa 指向类, 类的 isa 指向元类, 元类的 isa 指向自己对象 -> 类 -> 元类 -> 根元类 <-> 根元类
继承关系
: 所有类(包括元类)都是NSObject
的子类; 继承关系只存在于类与类之间;子类 -> 父类 -> ... -> NSObject
子类的元类 -> 父类的元类 -> ... -> NSObject 的元类 -> NSObject
注意:
NSObject 的元类是根元类, 根元类的父类是 NSObject
objc 源码
有了图, 再加上源码, 肯定是如虎添翼, 如鱼得水, 让你尽情的飞, 尽情的游. 这两个方法在上层接口中暴露出来是的两个对象方法, 实际在底层的实现分别有类方法和对象方法两种, 当类调用的时候, 底层走的是类方法, 类也可以叫类对象, 类对象是元类的实例对象, 这个大家应该不陌生. 下面是底层实现的代码.
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
对象方法分析
- (BOOL)isMemberOfClass:(Class)cls
这个方法实现还是比较简单的, self
(调用者)的类型与 cls
是否是同一个类, 是就返回 YES
, 不是就返回 NO
; 只对比本身的元类, 不会沿着继承链向上查找; 因为每个类对象在内存中只存在一份, 所以可以用 ==
判断;
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- (BOOL)isKindOfClass:(Class)cls
这个方法实现也不是很复杂, 首先判断的是 self
(调用者)的类型与 cls
是否是同一个类, 是就返回YES
, 不是就循环取出对应的父类继续比较, 一直沿着继承链向上找到 NSObject
, 如果还不是就取 NSObject
的父类, 因为 NSObject
的父类指向的是 nil
, 所以循环结束. 如果到循环结束都没有返回, 最后就返回 NO
; 简单来说就是从本类开始, 沿着继承链向上找, 只要有一个类与 cls
是同一个类, 就返回 YES
.
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
类方法分析
注意:
self
(调用者) 是类
, 或者说类对象
', 元类也是类.
+ (BOOL)isMemberOfClass:(Class)cls
这个类方法的实现其实与对象方法类似, 只是他对比的是元类
, self
(调用者)的元类型与 cls
是否是同一个类, 是就返回 YES
, 不是就返回 NO
; 也是只对比本身的元类, 不会沿着继承链向上查找; 在上层只有对象方法, 我认为就是源于类对象是元类的实例对象, 就是说类对象也是一个对象;
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
+ (BOOL)isKindOfClass:(Class)cls
这个方法实现其实与对象方法也类似, 只是对比的是元类及元类的继承链, 首先判断的是 self
(调用者)本身的元类型与 cls
是否是同一个类, 是就返回YES
, 不是就循环取出对应的父类的元类型继续比较, 一直沿着元类继承链向上找到根元类
, 因为根元类
的父类是 NSObject
, 所以最后还是会找到 NSObject
, 如果还不是就取 NSObject
的父类, 因为 NSObject
的父类指向的是 nil
, 所以循环结束. 如果到循环结束都没有返回, 最后就返回 NO
; 简单来说就是从本类的元类开始, 沿着元类的继承链向上找, 只要有一个元类(类)与 cls
是同一个类, 就返回 YES
.
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
验证
创建两个类, 分别是 Teacher
和Person
, Teacher
继承自 Person
, Person
继承自 NSObject
. 用现在的示例去验证上面的分析;
验证对象调用
testInstanceMethods
的示例和打印结果
void testInstanceMethods(void) {
Person *person = [Person alloc];
Class pClass = [Person class];
Class objCls = [NSObject class];
BOOL re1 = [person isKindOfClass: pClass];
BOOL re2 = [person isKindOfClass: objCls];
BOOL re3 = [person isMemberOfClass: pClass];
BOOL re4 = [person isMemberOfClass: objCls];
// 打印结果: 1110
NSLog(@"\n re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
}
re1
中person
对象的类型就是pClass
, 所以返回YES
;re2
中person
对象的类型不是objCls
, 但是沿着继承链向上最终会找到NSObject
, 所以最终也返回YES
re3
中person
对象的类型就是pClass
, 所以返回YES
;re4
中person
对象的类型显然不是objCls
, 也不会沿着继承链查找, 所以最终会返回NO
;
验证类调用
testClassMethods
的示例和打印结果
void testClassMethods(void) {
Class tClass = [Teacher class];
Class objCls = [NSObject class];
id pMetaClass = objc_getMetaClass("Person");
id tMetaClass = objc_getMetaClass("Teacher");
BOOL re1 = [tClass isKindOfClass: tClass];
BOOL re2 = [tClass isKindOfClass: tMetaClass];
BOOL re3 = [tClass isKindOfClass: pMetaClass];
BOOL re4 = [tClass isKindOfClass: objCls];
BOOL re5 = [tClass isMemberOfClass:tMetaClass];
BOOL re6 = [tClass isMemberOfClass:pMetaClass];
// 打印结果: 011110
NSLog(@"\n re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n re5 :%hhd\n re6 :%hhd\n",re1,re2,re3,re4,re5,re6);
}
re1
中tClass
类的元类型是tMetaClass
, 而不是tClass
本身, 所以会沿着tMetaClass
的继承链向上查找到根元类
, 因为根元类
的父类是NSObject
, 所以最后会找到NSObject
, 整个继承链都不会和tClass
不是同一个类, 所以最终返回NO
;re2
中tClass
类的元类型就是tMetaClass
, 所以返回YES
;re3
中tClass
类的元类型是tMetaClass
, 而不是pMetaClass
, 然后会沿着tMetaClass
的继承链向上查找, 因为tMetaClass
的父类是pMetaClass
, 所以会找到pMetaClass
, 此时判断条件成立, 所以返回YES
;re4
中tClass
类的类型是tMetaClass
, 而不是objCls
, 所以会沿着tMetaClass
的继承链向上查找到根元类
, 因为根元类
的父类是NSObject
, 所以最后会找到NSObject
, 此时判断条件成立, 所以返回YES
;re5
中tClass
类的元类型就是tMetaClass
, 所以返回YES
, 与re2
情况相同, 只是不会循环查找;re6
中tClass
类的元类型是tMetaClass
, 而不是pMetaClass
, 又不会沿着tMetaClass
的继承链向上查找, 所以是直接返回NO
;
总结
类对象也是对象, 所以我们统一从对象的角度出发来总结. 只是在用的时候有类对象和元类这个概念. 心中不忘 isa 走位图
, 这样我们就可以轻松应对;
- (BOOL)isKindOfClass:(Class)cls
首先对比对象本身的类是否就是传入的 cls
, 如果不是就沿着类的继承链向上查找, 直到 NSObject
, 一级一级对比, 如果遇到是传入的 cls
, 就返回YES
, 如果所有都不是传入的 cls
, 那么最终返回 NO
;
- (BOOL)isMemberOfClass:(Class)cls
直接对比对象本身的类是否就是传入的 cls
, 如果是传入的 cls
, 就返回YES
, 如果不是传入的 cls
, 就返回 NO
, 不会沿类继承链向上查找;
相信结合 isa 走位图
, 源码
, 源码分析
, 结论验证
这一系列骚操作之后, 你一定会对这两个方法有一个全新的认识, 终生难忘 😄😄😄😄😄😄
走过路过不要错过, 喜欢就点个赞吧, 谢谢了...