?? 今天從源碼來徹底了解這倆方法的區(qū)別统刮。
相信很多人應該都遇到過類似的面試題,日常開發(fā)中也用這倆方法做過不少判斷魏烫,比如后臺返回的數據是不是數組怖亭,是不是null沐鼠,是不是字典挚瘟,某個實例是不是指定的控制器等等。
BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [[Person class] isKindOfClass:[Person class]];
BOOL res4 = [[Person class] isMemberOfClass:[Person class]];
NSLog(@"%d %d %d %d", res1, res2, res3, res4);
BOOL res5 = [[[NSObject new]class] isKindOfClass:[NSObject class]];
BOOL res6 = [[[NSObject new]class] isMemberOfClass:[NSObject class]];
BOOL res7 = [[[Person new]class] isKindOfClass:[Person class]];
BOOL res8 = [[[Person new]class] isMemberOfClass:[Person class]];
NSLog(@"%d %d %d %d", res5, res6, res7, res8);
BOOL res9 = [[NSObject new] isKindOfClass:[NSObject class]];
BOOL res10 = [[NSObject new] isMemberOfClass:[NSObject class]];
BOOL res11 = [[Person new] isKindOfClass:[Person class]];
BOOL res12 = [[Person new] isMemberOfClass:[Person class]];
NSLog(@"%d %d %d %d", res9, res10, res11, res12);
這里面牽扯到的源碼如下:
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); 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;
}
先捋一下這幾個方法
- 類方法
+ (Class)class
返回的是他自身饲梭,即類對象乘盖。 - 實例方法
- (Class)class
返回的object_getClass(self)
,即實例對象的isa
憔涉,對這部分有點了解的應該知道订框,實例對象的isa
指向的就是類對象。 - 類方法
+ (BOOL)isMemberOfClass:(Class)cls
兜叨,判斷的是類對象的isa
(即元類)是否等于cls
穿扳。 - 實例方法
- (BOOL)isMemberOfClass:(Class)cls
,判斷的是實例對象調用class方法的返回值(即如上2国旷,也就是類對象
)是否與cls
相等矛物。 - 類方法
+ (BOOL)isKindOfClass:(Class)cls
,這里會先取類對象的isa (self->ISA())
跪但,類對象的isa
指向的是元類履羞,判斷元類是否與cls相等,而且這里是一個for循環(huán),不相等的話會往元類的父類(tcls = tcls->superclass)
循環(huán)去查找對比忆首。 - 實例方法
- (BOOL)isKindOfClass:(Class)cls
骨杂,這里是先取實例對象的isa ([self class]),也就是類對象
,判斷類對象與cls是否相等雄卷,不相等的話會往類對象的父類(tcls = tcls->superclass)
循環(huán)去查找對比搓蚪。
對實例對象,類對象丁鹉,元類不了解的可以看我前面的文章
捋清楚了上面幾個方法之后妒潭,再來看看開頭的面試題,是不是豁然開朗了揣钦。
下面我們一個個來康康雳灾。
BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
這里可以相當于[NSObject類對象 isKindOfClass NSObject類對象]
,即上述第5點冯凹,判斷的是NSObject的元類
是否等于類對象
谎亩,很明顯,肯定不等于宇姚,這是2個東西匈庭,接著去和元類的父類對比,那么按道理也是不相等的浑劳,但是如果對關系圖了解透徹的同學應該知道阱持,根元類的父類就是根類對象,那里這里會不太一樣魔熏,即NSObject的元類
的父類等于NSObject類對象
,那么最終會變成比較NSObject類對象是否等于NSObject類對象
衷咽,所以這里 res1的結果為 1.BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
這里可以相當于[NSObject類對象 isMemberOfClass NSObject類對象]
,即上述第3點蒜绽。判斷的是NSObject的元類是否等于NSObject類對象
镶骗,那必然不等于,所以這里 res2的結果為 0.BOOL res3 = [[Person class] isKindOfClass:[Person class]];
這里可以相當于[Person類對象 isKindOfClass Person類對象]
躲雅,即上述第3點鼎姊。判斷的是Person的元類
是否等于類對象
,必然不等于吏夯,接著去和元類的父類對比此蜈,也一樣是不等于的。這里不會向res1一樣噪生,最終也只是判斷NSObject類對象是否等于Person類對象
裆赵,所以res3 結果為 0。BOOL res4 = [[Person class] isMemberOfClass:[Person class]];
這里可以相當于[Person類對象 isMemberOfClass Person類對象]
跺嗽,即上述第3點战授。判斷的是Person的元類是否等于Person類對象
页藻,那必然不等于,所以這里 res2的結果為 0.BOOL res5 = [[[NSObject new]class] isKindOfClass:[NSObject class]];
這里首先調用實例對象的class
方法(即上述第2點)植兰,那么就相當于[NSObject類對象 isKindOfClass NSObject類對象]
份帐,那就是res1
的情況了,所以結果同res1
。BOOL res6 = [[[NSObject new]class] isMemberOfClass:[NSObject class]];
那么這里一樣結果同res2
楣导。BOOL res7 = [[[Person new]class] isKindOfClass:[Person class]];
結果同res3
废境。BOOL res8 = [[[Person new]class] isMemberOfClass:[Person class]];
結果同res4
。BOOL res9 = [[NSObject new] isKindOfClass:[NSObject class]];
這里相當于[NSObject實例對象 isKindOfClass NSObject類對象]
筒繁,即如上述第6點噩凹,判斷的是NSObject類對象與NSObject類對象是否相等
,那必然是相等的毡咏。所以res9的結果為 1驮宴。BOOL res10 = [[NSObject new] isMemberOfClass:[NSObject class]];
這里相當于[NSObject實例對象 isMemberOfClass NSObject類對象]
,即如上述第4點呕缭,判斷的也是NSObject類對象與NSObject類對象是否相等
堵泽,那必然是相等的,所以res10的結果為 1恢总。BOOL res11 = [[Person new] isKindOfClass:[Person class]];
結果同 res9迎罗。BOOL res12 = [[Person new] isMemberOfClass:[Person class]];
結果同 res10。
最終打印結果與理論是相符的离熏。