当前位置:   article > 正文

【iOS】isMemberOfClass&isKindOfClass_iskindofclass 和 ismemberofclass

iskindofclass 和 ismemberofclass


前言

认识这两个方法之前,首先要了解isa指向流程和继承链(【iOS】类对象的结构分析)关系,以便理解得更透彻

上经典图:

请添加图片描述

要注意的是:根类(NSObject)的元类isa是根元类,根元类的父类superclassNSObject

class方法

实例调用class方法就是获取isa所指:

- (Class)class {
    return object_getClass(self);
}

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

类调用class方法就是返回本身Class

typedef struct objc_class *Class;

+ (Class)class {
    return self;
}
  • 1
  • 2
  • 3
  • 4
  • 5

isMemberOfClass和isKindOfClass

objc4源码

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

实例方法分析

- (BOOL)isMemberOfClass:(Class)cls

此方法用于判断self(调用者)类型cls指定类)是否是同一个类,是就返回YES,否则返回NO。因为每个类对象在内存中只存在一份,所以可以用==判断

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}
  • 1
  • 2
  • 3

- (BOOL)isKindOfClass:(Class)cls

此方法用于判断self(调用者)类型cls指定类或者其父类)是否是同一个类,是就返回YES,否则就沿着继承链向上查找,只要有一个类与cls使用一个类,就返回YES,如果直到NSObject还没有找到,再向上就为nil,返回NO

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

类方法分析

类方法的调用者是Class类对象,按照isa指向,对比的应该是meta-class元类对象

+ (BOOL)isMemberOfClass:(Class)cls

此方法判断self(调用者)的isa元类)是否是指定元类(元类也是Class类型)

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}
  • 1
  • 2
  • 3

+ (BOOL)isKindOfClass:(Class)cls

此方法实现与其对象方法的实现类似,只是对比的是元类及元类的继承链
判断self(调用者)的isa元类)是否是指定类的元类或者其父类的元类,是就返回YES,否则就沿着继承链向上找到根元类,最后如果沿着superclass直到NSObject还没找到,再向上就为nil,返回NO

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

实例验证

下面通过调用上面的方法,来验证以上的分析:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface Person : NSObject

@end

@implementation Person

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        BOOL res1 = [[NSObject class] isKindOfClass: [NSObject class]];
        BOOL res2 = [[Person class] isKindOfClass: [Person class]];
        BOOL res3 = [[NSString class] isKindOfClass: [NSObject class]];
        
        NSLog(@"%d %d %d", res1, res2, res3);  // 1 0 1
        
        
        Person* person = [[Person alloc] init];
        BOOL res4 = [[Person class] isKindOfClass: [NSObject class]];
        BOOL res5 = [person isKindOfClass: [NSObject class]];
        NSLog(@"%d %d", res4, res5);  // 1 1
        
        
        //  获取一个类的元类的两种方式
//        Class objectMeta = objc_getMetaClass("NSObject");
        Class objectMeta = object_getClass([NSObject class]);
//        Class personMeta = objc_getClass("Person");
        Class personMeta = object_getClass([Person class]);
        
        
//        BOOL res6 = [[NSObject class] isMemberOfClass: objectMeta];  res6 == 1
        BOOL res6 = [[NSObject class] isMemberOfClass: [NSObject class]];
        BOOL res7 = [person isMemberOfClass: [NSObject class]];
//        BOOL res8 = [[Person class] isMemberOfClass: personMeta]; res8 == 1
        BOOL res8 = [[Person class] isMemberOfClass: [NSObject class]];
        BOOL res9 = [person isMemberOfClass: [Person class]];
        
        NSLog(@"%d %d %d %d" , res6, res7, res8, res9); // 0 0 0 1
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • isMemberOfClass
    • res1中调用的是类方法,沿着元类继承链找到NSObject类对象
    • res2中调用的是类方法,沿着元类继承链不会找到Person类对象
    • res3中调用的是类方法,沿着元类继承链找到NSObject类对象
    • res4中调用的是类方法,沿着元类继承链找到NSObject类对象
    • res5中调用的是对象方法,沿着继承链找到NSObject类对象
  • isKindOfClass
    • res6中调用的是类方法,对比的是元类对象,传入的是类对象
    • res7中调用的是对象方法,Person显然跟NSObject不是同一类
    • res8中调用的是类方法,对比的是元类对象,传入的是类对象
    • res9中调用的是对象方法,personPerson

上面的代码中,注释掉的res6res8中传入的是相应的元类对象,则结果为1

总结

那张isa指向和继承链流程图很经典!很重要!
结合源码会对这两个方法理解得更透彻
再分得清这两个方法的调用者是class(类对象)还是instance(实例对象)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/877513
推荐阅读
相关标签
  

闽ICP备14008679号