前言
这个归根结底还是在考察我们对isa走向图和类的继承的理解,也就是苹果官方这幅图:
接下来的函数调用流程请参考这张图。
1 isKindOfClass方法
1.1 objc_opt_isKindOfClass C函数
查看源码可发现,无论是谁调用isKindOfClass
方法都会进入这个C函数。(这个C函数位于NSObjective.mm
)
// Calls [obj isKindOfClass]
// 当obj调用isKindOfClass时,objc_opt_isKindOfClass会被触发
// obj是一个id类型,id是一个objc_object结构体指针,意味着,传进来的可以是时类,也可以是类的实例对象
// otherClass就是isKindOfClass的参数,我们当初传进去的cls
BOOL objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__if (slowpath(!obj)) return NO;Class cls = obj->getIsa(); // 此处的cls仅是obj的第一个isaif (fastpath(!cls->hasCustomCore())) {// otherClass 从obj的ISA开始,依次和ISA的父类比较,直到找到或者父类为nil结束// 当父类为nil意味着最后一个和otherClass比较的是NSObject根类。for (Class tcls = cls; tcls; tcls = tcls->superclass) {if (tcls == otherClass) return YES;}return NO;}
#endifreturn ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}
可知:
- 一切皆从调用者
obj
的isa
开始,然后顺着superclass
走下去,直到找到cls
或superclass
为nil
结束。 - 当
superclass
为nil
,意味着最后的根类NSObject
也不是cls
,返回flase
。
1.2 类SubClass调用+ (BOOL)isKinsOfClass:(Class)cls
流程:
- 从类的
isa
——元类开始,判断它不是cls
; - 如果是,返回
true
; - 如果不是,继续用元类的
superclass
和cls
比较,看是不是cls
; - 直到根类
NSObject
也比较完。
判断顺序: SubClass
与 MetaClass->MetaClass->...->RootMetaClass->NSObject
。
总结:
- 判断
cls
是不是 元类->父类的元类->父父类的元类->…->根元类->NSObject
(元类的superclass
继承链)其中一个。 cls
传除NSObject.class
外的任意类对象均为false
。
1.3 元类MetaClass 调用+ (BOOL)isKinsOfClass:(Class)cls
流程:
MetaClass
的ISA
指向RootMetaClass
,所以从RootMetaClass
开始比较判断是不是我们传入的cls;- 如果不是,再看根类
NSObject
是不是,如果NSObject
也不是,就彻底没有了,返回false
。
判断顺序:MetaClass
与 RootMetaClass->NSObject
。
总结:
- 判断
cls
是不是根元类->NSObject
中的任意一个。
1.4 对象obj 调用- (BOOL)isKinsOfClass:(Class)cls
流程:
- 从
isa
指向的类对象开始,判断是不是cls
; - 如果不是,看类对象的父类,逐级判断是不是
cls
; - 直到找到返回
true
,或者判断到NSObject
依然不是,返回false
结束。
判断顺序: object
与 SubClass -> SubClass ->...->NSObject
。
总结:
- 判断cls是不是 类对象->父类->…->NSObject (superclass继承链)其中一个。
2 isMemberOfClass
2.1 类对象SubClass调用+ (BOOL)isMemberOfClass
源码:
+ (BOOL)isMemberOfClass:(Class)cls {return self->ISA() == cls;
}
不用像isKindOfClass循环直到找到或nil,他只要比较cls是不是我当前的isa指向,是返回true,不是返回false。
判断:SubClass
与MetaClass
。
2.2 元类MetaClass 调用+ (BOOL)isMemberOfClass
因为元类的isa只指向根元类NSObejct ,所以除了NSObject的类SubClass以外,传入任何类对象也都是false。
验证传入NSObject的类SubClass的结果:
void demo(void) {
// BOOL re1 = [[NSObject class] isKindOfClass:[NSObject class]];Class rootMetaClass = object_getClass([NSObject class]);NSLog(@"%d", [[NSObject class] isMemberOfClass:rootMetaClass]);
}
结果:
2.3 对象obj调用 -(BOOL)isMemberofClass:(Class)clss
- (BOOL)isMemberOfClass:(Class)cls
底层源码:
- (BOOL)isMemberOfClass:(Class)cls {return [self class] == cls;
}
- (Class)class {return object_getClass(self); // 获取当前的isa指向的类
}
只要判断对象的isa,也就是图中的SubClass是不是我们传入的cls。
3. 测试
void demo(void) {BOOL f1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];BOOL f2 = [(id)[MyClass class] isKindOfClass:[MyClass class]];BOOL f3 = [(id)[MySuperClass class] isKindOfClass:[MySuperClass class]];BOOL f4 = [(id)[MyClass class] isKindOfClass:[MySuperClass class]];BOOL f5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];BOOL f6 = [(id)[MyClass alloc] isKindOfClass:[NSObject class]];BOOL f7 = [(id)[MySuperClass alloc] isKindOfClass:[NSObject class]];NSLog(@"NSObjectClass ISKindOf NSObjectClass:%d", f1);NSLog(@"MyClassClass ISKindOf MyClassClass:%d", f2);NSLog(@"MySuperClassClass ISKindOf MySuperCassClass:%d", f3);NSLog(@"MyClassClass ISKindOf MySuperClassClass:%d", f4);NSLog(@"NSObjectObj ISKindOf NSObjectClass:%d", f5);NSLog(@"MyClassObj ISKindOf NSObjectClass:%d", f6);NSLog(@"MySuperClassObj ISKindOf NSObjectClass:%d", f7);}
测试结果: