【iOS笔记】【16】isKindOfClass与isMemberOfClass

本文最后更新于:2021年12月22日 中午

【主页】系列文章目录

【iOS笔记】系列目录


一 Code

说明:Test直接继承自NSObject

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
- (void)testClassISA {

id b1 = [NSObject class];

id b2 = [NSObject class];

id b3 = [[NSObject new] class];

// NSObject, NSObject, NSObject
NSLog(@"[NSObject class] = %@ , %@, %@", b1,b2,b3);

/*
① [NSObject class] => NSObject
② +isKindOfClass => 沿着(元类)继承链查找isa
③ NSObject->isa => NSObject元类
④ NSObject元类->superClass(沿着继承链) => NSObject
⑤ ①等于④ => true
*/
BOOL res1 = [(id)[NSObject class] isKindOfClass:(id)[NSObject class]];

/*
① [NSObject class] => NSObject
② +isMemberOfClass => 查找isa(元类)
③ NSObject->isa => NSObject元类
④ ①不等于③ => false
*/
BOOL res2 = [(id)[NSObject class] isMemberOfClass:(id)[NSObject class]];

/*
① [NSObject new] => 对象obj
② [obj class] => 对象的isa => NSObject
③ +isKindOfClass => 沿着(元类)继承链查找isa
④ NSObject->isa => NSObject元类
⑤ NSObject元类->superClass(沿着继承链) => NSObject
⑥ ②等于⑤ => true
*/
BOOL res3 = [(id)[[NSObject new] class] isKindOfClass:(id)[NSObject class]];

/*
① [NSObject new] => 对象obj
② [obj class] => NSObject
③ +isMemberOfClass => 查找isa(元类)
④ NSObject->isa => NSObject元类
⑤ ②不等于④ => false
*/
BOOL res4 = [(id)[[NSObject new] class] isMemberOfClass:(id)[NSObject class]];

/*
① [NSObject new] => 对象obj
② [NSObject class] => NSObject
③ -isKindOfClass => 沿着(类)继承链查找isa
④ obj->isa => NSObject
⑤ ②等于④ => true
*/
BOOL res5 = [(id)[NSObject new] isKindOfClass:(id)[NSObject class]];

/*
① [NSObject new] => 对象obj
② [NSObject class] => NSObject
③ -isMemberOfClass => 查找isa(类)
④ obj->isa => NSObject
⑤ ②等于④ => true
*/
BOOL res6 = [(id)[NSObject new] isMemberOfClass:(id)[NSObject class]];

/*
① [Test class] => Test
② +isKindOfClass => 沿着(元类)继承链查找isa
③ Test->isa => Test元类
④ ①不等于④ => 沿着(元类)继承链查找isa
⑤ Test元类->superClass => NSObject元类
⑥ ①不等于⑤ => 沿着(元类)继承链查找isa
⑦ NSObject元类->superClass => NSObject
⑧ ①不等于⑦ => 沿着(元类)继承链查找isa
⑨ NSObject->superClass => nil
⑩ ①不等于⑨,且查询到nil,结束查找链 => false
*/
BOOL res7 = [(id)[Test class] isKindOfClass:(id)[Test class]];

/*
① [Test class] => Test
② +isMemberOfClass => 查找isa(元类)
③ Test->isa => Test元类
④ ①不等于③ => false
*/
BOOL res8 = [(id)[Test class] isMemberOfClass:(id)[Test class]];

/*
① [Test class] => Test
② [Test new] => obj
③ [obj class] => Test
④ +isKindOfClass => 沿着(元类)继承链查找isa
⑤ Test->isa => Test元类
⑥ ①不等于⑤ => 沿着(元类)继承链查找isa
⑦ Test元类->superClass => NSObject元类
⑧ ①不等于⑦ => 沿着(元类)继承链查找isa
⑨ NSObject元类->superClass => NSObject
⑩ ①不等于⑨ => 沿着(元类)继承链查找isa
⑪ NSObject->superClass => nil
⑫ ①不等于⑪,且查询到nil,结束查找链 => false
*/
BOOL res9 = [(id)[[Test new] class] isKindOfClass:(id)[Test class]];

/*
① [Test class] => Test
② [Test new] => obj
③ [obj class] => Test
④ +isMemberOfClass => 查找isa(元类)
⑤ Test->isa => Test元类
⑥ ①不等于⑤ => false
*/
BOOL res10 = [(id)[[Test new] class] isMemberOfClass:(id)[Test class]];

/*
① [Test class] => Test
② [Test new] => obj
② -isKindOfClass => 沿着(类)继承链查找isa
③ obj->isa => Test
④ ①等于③ => true
*/
BOOL res11 = [(id)[Test new] isKindOfClass:(id)[Test class]];

/*
① [Test class] => Test
② [Test new] => obj
③ -isMemberOfClass => 查找isa(类)
④ obj->isa => Test
⑤ ①等于④ => true
*/
BOOL res12 = [(id)[Test new] isMemberOfClass:(id)[Test class]];

// 1, 0, 1, 0, 1, 1
NSLog(@"%d, %d, %d, %d, %d, %d",res1, res2, res3,res4,res5, res6);

// 0, 0, 0, 0, 1, 1
NSLog(@"%d, %d, %d, %d, %d, %d",res7, res8, res9,res10,res11, res12);

}

二 源码

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/// 类方法,返回自身
+ (Class)class {

return self;

}

/// 实例方法,查找isa(类)
- (Class)class {

return object_getClass(self);

}

Class object_getClass(id obj) {

if (obj) return obj->getIsa();

else return Nil;

}

inline Class objc_object::getIsa() {

if (isTaggedPointer()) {
uintptr_t slot = ((uintptr_t)this >> TAG_SLOT_SHIFT) & TAG_SLOT_MASK;

return objc_tag_classes[slot];

}

return ISA();

}

inline Class objc_object::ISA() {

assert(!isTaggedPointer());

return (Class)(isa.bits & ISA_MASK);

}

/*
这是一个类似于for (int i = 0; i < 3; i ++)的for循环
self->ISA()得到当前类对象的类——元类,初始化tcls
只要tcls有值就可以继续循环,即当tcls为nil时结束for循环
取得tcls的父类,作为它的新值,继续下一次循环
当for循环中有一次tcls == cls,返回YES
结束for循环时还没满足条件就返回NO
*/
/// +isKindOfClass是元类及其父类 vs 类
/// 类方法,沿着继承链,去判定isa(类对象isa是元类)和参数是否相等
+ (BOOL)isKindOfClass:(Class)cls {

for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {

if (tcls == cls) return YES;

}

return NO;

}

/// -isKindOfClass是类本身及其父类 vs 类
/// 实例方法,沿着继承链,去判定isa(实例对象isa是类)和参数是否相等
- (BOOL)isKindOfClass:(Class)cls {

for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {

if (tcls == cls) return YES;

}

return NO;
}

/*
self->ISA()得到当前类对象的类——元类,和类本身cls进行比较
相较于+isKindOfClass少了父类的比较,因此+isMemberOfClass为YES时可以得到+isKindOfClass为YES
*/
/// +isMemberOfClass是元类 vs 类
/// 类方法,判定isa(元类)和参数是否相等
+ (BOOL)isMemberOfClass:(Class)cls {

return self->ISA() == cls;

}

/// -isMemberOfClass是类本身 vs 类
/// 实例方法,判定isa(类)和参数是否相等
- (BOOL)isMemberOfClass:(Class)cls {

return [self class] == cls;

}

总结:

    1. object_getClass(obj)返回的是obj的isa指针;
    1. [obj class]则分两种情况:
  • obj为实例对象

调用的是实例方法:- (Class)class,返回的obj对象中的isa指针;

  • obj为类对象(包括元类和根类以及根元类)

调用的是类方法:+ (Class)class,返回的结果为其本身。

参考:【iOS笔记】【3】class方法和objc_getClass方法

1.isKindOfClass

是否是当前类或当前类的子类实例

Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class.

判定依据

实例对象调用isKindOfClass

沿继承链获取isa(类对象),判定class与继承链上获取的isa是否有相等的

类对象调用isKindOfClass

沿继承链获取isa(元类对象),判定class与继承链上获取的isa是否有相等的

2.isMemberOfClass

是否是给定类的实例

Returns a Boolean value that indicates whether the receiver is an instance of a given class.

isMemberOfClass的源码实现是拿到自己的isa指针和自己比较,是否相等。

图1


总结一下判定流程
结合上图1,共有三列,第一列实例对象,第二列类对象,第三列元类对象。

  • + (BOOL)isKindOfClass:(Class)cls;
    类方法,沿着继承链,去判定isa(类对象isa是元类)和参数是否相等,即判定第三列的所有元类以及根元类的父类NSObject是否有能和参数匹配的。
    参见res7的判定流程
  • - (BOOL)isKindOfClass:(Class)cls;
    实例方法,沿着继承链,去判定isa(实例对象isa是类)和参数是否相等,即判定第二列的所有类以及根类NSObject是否有能和参数匹配的。
    参见res5的判定流程
  • + (BOOL)isMemberOfClass:(Class)cls;
    类方法,判定isa(元类)和参数是否相等,只判定一次,判定元类,即第三列是否有能和参数匹配的。
    参见res2的判定流程
  • - (BOOL)isMemberOfClass:(Class)cls;
    实例方法,判定isa(类)和参数是否相等,只判定一次,判定元类,即第二列是否有能和参数匹配的。
    参见res6的判定流程

联系方式

邮箱: xiebangyao_1994@163.com

相关账号: