【iOS】isKindOfClass和isMemberOfClass方法

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前言

这个归根结底还是在考察我们对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的第一个isa
    if (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;
    }
#endif
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}

可知

  1. 一切皆从调用者objisa开始然后顺着superclass走下去直到找到clssuperclassnil结束。
  2. superclassnil意味着最后的根类NSObject也不是cls返回flase

1.2 类SubClass调用+ (BOOL)isKinsOfClass:(Class)cls

流程

  1. 从类的isa——元类开始判断它不是cls
  2. 如果是返回true
  3. 如果不是继续用元类的superclasscls比较看是不是cls
  4. 直到根类NSObject也比较完。

判断顺序 SubClassMetaClass->MetaClass->...->RootMetaClass->NSObject

总结

  • 判断cls是不是 元类->父类的元类->父父类的元类->…->根元类->NSObject 元类的superclass继承链其中一个。
  • cls 传除NSObject.class外的任意类对象均为false

1.3 元类MetaClass 调用+ (BOOL)isKinsOfClass:(Class)cls

流程

  1. MetaClassISA 指向 RootMetaClass ,所以从 RootMetaClass 开始比较判断是不是我们传入的cls
  2. 如果不是再看根类NSObject是不是如果NSObject也不是就彻底没有了返回false

判断顺序MetaClassRootMetaClass->NSObject

总结

  • 判断cls是不是 根元类->NSObject 中的任意一个。

1.4 对象obj 调用- (BOOL)isKinsOfClass:(Class)cls

流程

  1. isa指向的类对象开始判断是不是cls
  2. 如果不是看类对象的父类逐级判断是不是cls
  3. 直到找到返回true或者判断到NSObject依然不是返回false结束。

判断顺序 objectSubClass -> 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。

判断SubClassMetaClass

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);
    
}

测试结果
在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6