美文网首页面试技术基础应用
iOS底层-isKindOfClass与isMemberOfCl

iOS底层-isKindOfClass与isMemberOfCl

作者: Engandend | 来源:发表于2019-12-17 15:35 被阅读0次

    isMemberOfClass:isKindOfClass:其实在平常的开发中,用的还是比较多的,今天从底层来分析他的实现究竟是什么样的以及需要注意的点

    1、 isKindOfClass

    分为类方法和实例方法
    - (BOOL)isKindOfClass:(Class)cls
    + (BOOL)isKindOfClass:(Class)cls
    先看看源码

    + (BOOL)isKindOfClass:(Class)cls {
        for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
            if (tcls == cls) return YES;
        }
        return NO;
    }
    
    - (BOOL)isKindOfClass:(Class)cls {
        for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
            if (tcls == cls) return YES;
        }
        return NO;
    }
    

    类方法是对cls的元类/根元类的父类进行递归
    实例方法是对cls的父类进行递归
    关于元类、根元类以及父类的走向, 可以参照isa探索

    代码示例

    前提: Person:NSObject ------ Student:Person
    代码:

    //类方法
    BOOL kindObj = [[NSObject class]    isKindOfClass:[NSObject class]];  //1
    BOOL kindPer = [[Person class]      isKindOfClass:[NSObject class]];  //2
    BOOL kindStu = [[Student class]     isKindOfClass:[NSObject class]];  
    BOOL kindTemp = [[Student class]    isKindOfClass:[Person class]];    //3 *这个分析请注意⚠️
    NSLog(@"kindObj = %@ kindPer = %@ kindStu = %@ kindTemp = %@",@(kindObj),@(kindPer),@(kindStu),@(kindTemp));
    
    打印结果:
    kindObj = 1 kindPer = 1 kindStu = 1 kindTemp = 0
    
    //实例方法
    BOOL iskindStu = [[Student new] isKindOfClass:[Student class]];
    BOOL iskindPer = [[Student new] isKindOfClass:[Person class]];
    BOOL iskindObj = [[Student new] isKindOfClass:[NSObject class]];  //4
    NSLog(@"iskindStu = %@ iskindPer = %@ iskindObj = %@",@(iskindStu),@(iskindPer),@(iskindObj));
    
    打印结果:
    iskindStu = 1 iskindPer = 1 iskindObj = 1
    

    我们来参照isa走向图和源码来分析为什么打印结果是这样的

    isa走向图
    1、[[NSObject class] isKindOfClass:[NSObject class]]; 这个之所以打印为1 并不是我们想象的左右两边一样,所以打印1,而是因为NSObject的更元类的父类是NSObject本身

    分析:
    [object_getClass((id)self)] 意思是 [NSObjet class] 的元类,在图中 就是 root class (class) 的isa 指向的是 root class(meta)
    root class(meta)的父类 是 root class (class)

    2、[[Student class] isKindOfClass:[NSObject class]];

    分析:
    [object_getClass((id)self)] 的 superclass 依次是:Subclass(meta) -> Superclass(meta) -> root class(meta) -> root class(class)
    在这里 isKindOfClass:[NSObject class] 就是 root class(class)

    3、[[Student class] isKindOfClass:[Person class]];
    分析:
    [object_getClass((id)self)] 的 superclass 依次是:Subclass(meta) -> Superclass(meta) -> root class(meta) -> root class(class)
    在这里 isKindOfClass:[Person class] 是 Superclass(class),这个过程中 ,都没有指向Superclass(class),所以返回的是NO

    4、[[Student class] isKindOfClass:[Person class]]; 实例方法很好理解

    分析:
    Student 继承Person Person 继承NSObject,所以 [Student new] 的父类是Person ,父类的父类是 NSObject,所以结果都是1

    2、isMemberOfClass

    分为类方法和实例方法
    - (BOOL)isMemberOfClass:(Class)cls
    + (BOOL)isMemberOfClass:(Class)cls
    先看看源码

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

    isMemberOfClass相对于isKindOfClass来说,只是做了一层判断,而没有递归

    代码示例

    前提: Person:NSObject ------ Student:Person
    代码:

    //类方法
    BOOL memObj = [[NSObject class]    isMemberOfClass:[NSObject class]];
    BOOL memPer = [[Person class]      isMemberOfClass:[NSObject class]];
    BOOL memStu = [[Student class]     isMemberOfClass:[NSObject class]];
    BOOL memTemp = [[Student class]    isMemberOfClass:[Person class]];    //1
    NSLog(@"memObj = %@ memPer = %@ memStu = %@ memTemp = %@",@(memObj),@(memPer),@(memStu),@(memTemp));
    
    打印结果:
    memObj = 0 memPer = 0 memStu = 0 memTemp = 0
    
    //实例方法
    BOOL isMemStu = [[Student new] isMemberOfClass:[Student class]];
    BOOL isMemPer = [[Student new] isMemberOfClass:[Person class]];
    BOOL isMemObj = [[Student new] isMemberOfClass:[NSObject class]]; //2
    NSLog(@"iskindStu = %@ iskindPer = %@ iskindObj = %@",@(iskindStu),@(iskindPer),@(iskindObj));
    
    打印结果:
    isMemStu = 1 isMemPer = 0 isMemObj = 0
    

    1、[[Student class] isMemberOfClass:[Person class]]

    分析: object_getClass((id) [Student class]) 得到的是 Subclass(meta) ,是根元类,所以打印结果都是NO

    2、[[Student new] isMemberOfClass:[Person class]]

    分析:
    object_getClass((id) [Student new]) 得到的是 Subclass(class) , 在上面的类方法示例中,只有[Student class] 是 Subclass(class),所以其他都是NO。

    3、 注意事项:

    1、对于 isKindOfClass 的类方法和示例方法,理解起来稍微不同,不过知道了isa走向图和源码,就可以分析出来为什么了。
    BOOL kindObj = [[NSObject class] isKindOfClass:[NSObject class]];
    BOOL kindTemp = [[Student class] isKindOfClass:[Student class]];
    打印结果为什么一个是YES,一个是NO,isKindOfClass基本就理解透了

    比如 [[Student class] isKindOfClass:[NSObject class]]; 之所以打印结果是YES,是由于 NSObject的元类的父类 指向的是NSObject class 本身

    2、类族
    BOOL ismem = [[NSMutableArray new] isMemberOfClass:[NSArray class]]; 的结果是NO,虽然NSmutableArray 是继承 NSArray,但是需要了解的一个概念:类族;可自行Google。
    类族包括:NSString、 NSArray、NSDictionary 、NSData、NSNumber等

    相关文章

      网友评论

        本文标题:iOS底层-isKindOfClass与isMemberOfCl

        本文链接:https://www.haomeiwen.com/subject/mvhsnctx.html