面试技术基础应用

iOS底层-isKindOfClass与isMemberOfCl

2019-12-17  本文已影响0人  Engandend

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等

上一篇下一篇

猜你喜欢

热点阅读