相關(guān)鏈接:objc4-750配置下載教程
日常開(kāi)發(fā)中,我們想必會(huì)經(jīng)常通過(guò)isKindOfClass和isMemberOfClass去處理一些邏輯判斷,但是我們真的了解它們嗎?
話不多說(shuō)我們直接上場(chǎng)景:
@interface Person : NSObject
@end
@implementation Person
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL re3 = [(id)[Person class] isKindOfClass:[Person class]];
BOOL re4 = [(id)[Person class] isMemberOfClass:[Person class]];
NSLog(@" re1 :%hhd re2 :%hhd re3 :%hhd re4 :%hhd ",re1,re2,re3,re4);
}
return 0;
}
輸出結(jié)果:
2019-08-21 17:01:00.054439+0800 001-isKindOfClass&isMemberOfClass[25960:1615638] re1 :1 re2 :0 re3 :0 re4 :0
接下來(lái)我們通過(guò)objc源碼來(lái)分析為什么會(huì)是輸出這個(gè)樣的一個(gè)結(jié)果~
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self 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;
}
由源碼得知:
在isKindOfClass中有一個(gè)循環(huán),先判斷當(dāng)前類是否等于元類,不等就繼續(xù)循環(huán)取元類的父類進(jìn)行判斷,不等再繼續(xù)取父類,如此循環(huán)下去。
然而此時(shí)我們需要上isa走向圖:

[NSObject class] 調(diào)用 isKindOfClass,第一次判斷先判斷NSObject 和 NSObject的元類是否相等,從圖上我們也可以看出,NSObject的元類是根元類。接著第二次循環(huán)判斷NSObject與根元類的父類是否相等。還是從那張圖上面我們可以看到:根元類 的父類也就是NSObject本身。所以第二次循環(huán)相等,于是第一行res1輸出應(yīng)該為YES。
[Person class] 調(diào)用 isKindOfClass,第一次for循環(huán),Person的元類與[Person class]不等,第二次for循環(huán),Person元類的父類 指向的是 NSObject Meta Class(根元類), 和[Person class]不相等。第三次for循環(huán),根元類指向的是NSObject,和 [Person Class] 不相等。第四次循環(huán),NSObject Class 的父類 指向 nil, 和 Person Class不相等。第四次循環(huán)之后,退出循環(huán),所以第三行的res3輸出為NO。
isMemberOfClass的源碼實(shí)現(xiàn)是拿到自己的isa指針和自己比較,是否相等。
第二行 isa 指向 NSObject 的 元類,所以和 NSObject不相等。第四行,isa指向Person的元類,和Perosn Class也不等,所以第二行res2和第四行res4都輸出NO。