对isKindOfClass和isMemberOfClass调试和分析

369 阅读5分钟

一、class返回对象lldb调试

首先看代码1

 BOOL re1 = [[NSObject class] isKindOfClass:[NSObject class]];

[类名 class]返回的是什么东西,我们先查看objc源码

+ (Class)class {
    return self;
}

源码很简单,返回self就是Class本身,通过lldb调试探究一下 image.png 打印下class1

(lldb) x/4gx class1
0x100379140: 0x00000001003790f0 0x0000000000000000
0x100379150: 0x00010001012bd3f0 0x0001801000000000

po一下isa

(lldb) po 0x00000001003790f0
NSObject

再对isa进行x/4gx

(lldb) x/4gx 0x00000001003790f0
0x1003790f0: 0x00000001003790f0 0x0000000100379140
0x100379100: 0x0003000100717d30 0x0001e03400000000

都是0x00000001003790f0,继续po

(lldb) po 0x00000001003790f0
NSObject

isa还是指向了自己,就是NSObject根类的元类——根元类,从下面这幅图可以看出

isa流程图.png

因为NSObject是特殊情况,那可以继续探究,ApplePerson继承于NSObject

@interface ApplePerson : NSObject{
    NSString *salary;
}

image.png

打印下内存

(lldb) x/4gx class2
0x100008498: 0x0000000100008470 0x0000000100379140
0x1000084a8: 0x000000010036d0e0 0x0000802800000000

po 一下

po 0x0000000100008470
ApplePerson

ApplePerson 没问题,再x/4gx一下

(lldb) x/4gx 0x0000000100008470
0x100008470: 0x00000001003790f0 0x00000001003790f0
0x100008480: 0x000000010036d0e0 0x0000e03400000000

再po一下

(lldb) po 0x00000001003790f0
NSObject

拿到了NSObject

image.png

现在很清晰,[类名 class]返回了类对象,探究和源码一致,接下来,

二、类方法 isKindOfClass

现在我们看isKindOfClass,翻阅源码

+ (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;
}

有两个方法一个类方法,一个实例方法,先看类方法

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

For循环里面,Class tcls = self->ISA(); 很明显tcls是拿到类对象的元类,和传进来的类进行对比,如果不对,再取tcls的父类进行对比,第一次循环

tcls = NSObject类的元类即根元类,而cls是NSObject类,所以不相等;
这时第二轮For循环,再取NSObject根元类的父类跟NSObject类对比,由于NSObject根元类的父类就是NSObject类,所以相等,下面的图也可以看得出来

image.png

再看下代码2

BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; 
NSLog(@"re1 = %hhd",re1);

运行下

re1 = 1

再测试普通类代码

BOOL re2 = [[ApplePerson class] isKindOfClass:[ApplePerson class]];
NSLog(@"re2 = %hhd",re2);

[ApplePerson class]得到ApplePerson类和[ApplePerson class]->isa类比,即ApplePerson的元类比,肯定匹配不了,那继续循环 --> 和ApplePerson的元类的父类比,即和根元类NSObject类比 --> 匹配不上,那继续循环,和根元类NSObject的父类比NSObject类比 --> 匹配不上,NSObject再上去就是nil,循环结束,返回NO,运行下

re2 = 0

三、实例方法 isKindOfClass

代码3

BOOL re3 = [[NSObject alloc] isKindOfClass:[NSObject class]];
NSLog(@"re3 = %hhd",re3);

先看下源码

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

分析一下,Class tcls = [[NSObject alloc] class] 实例对象class方法获取到类对象,和[NSObject class]获取到类方法是一样的,跑下代码

re3 = 1

代码4

BOOL re4 = [[ApplePerson alloc] isKindOfClass:[ApplePerson class]];
NSLog(@"re4 = %hhd",re4);

同理,ApplePerson的实例对象走class方法返回ApplePerson类,和[ApplePerson class]是一致的,跑下代码

re4 = 1

再看下for循环

for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }

如果没找到的话,会拿tcls的父类和cls比,如果tcls所属类是cls类的子类,那也是返回1,验证一波 (ApplePerson的父类是NSObject)
代码 5

BOOL re5 = [[ApplePerson alloc] isKindOfClass:[NSObject class]];
NSLog(@"re5 = %hhd",re5);

运行,打印

re5 = 1

四、类方法 isMemberOfClass

代码 6

BOOL re6 = [[NSObject class] isMemberOfClass:[NSObject class]];
NSLog(@"re6 = %hhd",re6);

查看源码

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

拿到类的isa的类,那就是拿到类的元类,所以self->ISA()是元类,而cls是类,所以并不相等,运行一下

re6 = 0

再看代码7

BOOL re7 = [[ApplePerson class] isMemberOfClass:[ApplePerson class]];
NSLog(@"re7 = %hhd",re7);

拿ApplePerson元类和ApplePerson类比,肯定不一样,运行代码

re7 = 0

五、实例方法 isMemberOfClass

代码8

BOOL re8 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
NSLog(@"re8 = %hhd",re8);

看源码

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

对象class方法得到类对象和cls相比较,[[NSObject alloc] class]的得到NSObject类对象和[NSObject class]是一样的,验证一波

re8 = 1

代码9

BOOL re9 = [[ApplePerson alloc] isMemberOfClass:[ApplePerson class]];
NSLog(@"re9 = %hhd",re9);

也是一样得到ApplePerson的类对象和传入的是一样的

re9 = 1